diff --git a/.changeset/README.md b/.changeset/README.md deleted file mode 100644 index e5b6d8d..0000000 --- a/.changeset/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Changesets - -Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works -with multi-package repos, or single-package repos to help you version and publish your code. You can -find the full documentation for it [in our repository](https://github.com/changesets/changesets) - -We have a quick list of common questions to get you started engaging with this project in -[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/adopt-ccc-udt.md b/.changeset/adopt-ccc-udt.md deleted file mode 100644 index afa1c66..0000000 --- a/.changeset/adopt-ccc-udt.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@ickb/core": major -"@ickb/dao": minor -"@ickb/order": major -"@ickb/utils": major -"@ickb/sdk": major ---- - -Adopt CCC udt.Udt as IckbUdt base class, replacing homegrown UDT infrastructure - -- Rewrite `IckbUdtManager` as `IckbUdt` extending CCC's `udt.Udt` base class -- Accept code OutPoints instead of pre-built CellDep arrays -- Override `infoFrom()` to value iCKB's three cell representations (xUDT, receipt, deposit) -- Remove `udtHandler` parameter from `LogicManager` and `OwnedOwnerManager` -- Replace `UdtHandler` with plain `udtScript` in `OrderManager` -- Delete `UdtHandler`, `UdtManager`, `UdtCell`, `ErrorTransactionInsufficientCoin` from `@ickb/utils` -- Widen `DaoManager.isDeposit()` to accept `CellAny` diff --git a/.changeset/config.json b/.changeset/config.json deleted file mode 100644 index 4fa92d7..0000000 --- a/.changeset/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json", - "changelog": ["@changesets/changelog-github", { "repo": "ickb/stack" }], - "prettier": false, - "commit": false, - "fixed": [], - "linked": [], - "access": "public", - "baseBranch": "master", - "updateInternalDependencies": "patch", - "ignore": [] -} diff --git a/.changeset/remove-local-utility-functions.md b/.changeset/remove-local-utility-functions.md deleted file mode 100644 index f23f537..0000000 --- a/.changeset/remove-local-utility-functions.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@ickb/utils": major -"@ickb/order": patch -"@ickb/sdk": patch ---- - -Remove local max, min, gcd, hexFrom, isHex utility functions -- replaced by CCC equivalents - -- Delete `max`, `min`, `gcd`, `hexFrom`, `isHex` from `@ickb/utils` public API -- Replace `max()` call sites with `Math.max()` in `@ickb/order` and `@ickb/sdk` -- Replace `gcd()` call site with `ccc.gcd()` in `@ickb/order` -- Replace `hexFrom(entity)` call sites with `entity.toHex()` in `@ickb/order` and `@ickb/sdk` -- Replace `hexFrom(bytes)` call site with `ccc.hexFrom()` in faucet app -- Update `unique()` internal implementation to use `entity.toHex()` instead of local `hexFrom()` diff --git a/.changeset/remove-smarttx-capacitymgr.md b/.changeset/remove-smarttx-capacitymgr.md deleted file mode 100644 index 227e1d8..0000000 --- a/.changeset/remove-smarttx-capacitymgr.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@ickb/utils": major -"@ickb/core": major -"@ickb/dao": major -"@ickb/order": major -"@ickb/sdk": major ---- - -Remove SmartTransaction and CapacityManager in favor of plain TransactionLike - -- Delete `SmartTransaction` class and `CapacityManager` class from `@ickb/utils` -- Replace all `SmartTransaction` parameters with `ccc.TransactionLike` across all packages -- Inline `getHeader`/`addHeaders` helpers and remove from public API -- Consolidate 7 inline DAO output limit checks into `assertDaoOutputLimit` in CCC core -- Change `UdtHandler.completeUdt` return type from `[number, boolean]` to `[ccc.Transaction, number, boolean]` -- Replace local CCC patch with upstream PR #359 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index e8a5209..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,78 +0,0 @@ -// Instructions to use this devcontainer: -// 0. Make sure Docker or Podman is running. -// 1. Install the VS Code extension "Dev Containers" (ms-vscode-remote.remote-containers). -// 2. Open the Command Palette (Shift+Ctrl+P / Shift+Cmd+P) and run "Dev Containers: Reopen in Container", -// alternatively "Dev Containers: Open Folder in Container". -// 3. When finished, run "Dev Containers: Close Remote Connection" from the Command Palette to stop the container. -{ - "name": "Dev Environment", - - "image": "mcr.microsoft.com/devcontainers/typescript-node:24", - - "containerEnv": { - "DEVCONTAINER": "true", - "DEVCONTAINERS_NO_TELEMETRY": "true", - "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", - "CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY": "1", - "DO_NOT_TRACK": "1", - "NEXT_TELEMETRY_DISABLED": "1", - "NO_UPDATE_NOTIFIER": "1", - "npm_config_update_notifier": "false" - }, - - // Persisted volumes to speed installs and avoid repeated network requests - "mounts": [ - // Share a pnpm store cache volume to speed package resolution and install times across projects/containers - "source=pnpm-cache,target=${containerWorkspaceFolder}/.pnpm-store,type=volume" - ], - - // Run once after the container filesystem is created. - "postCreateCommand": { - // Enable corepack and fix workspace ownership for non-root user - "permissions": "sudo corepack enable && sudo chown -R node:node /home/node ${containerWorkspaceFolder}", - // Needed for AI Coworker extension to work with a pnpm installation - "aliases": "echo \"alias claude='pnpm coworker'\" >> ~/.bash_aliases", - // Install GSD - "gsd": "pnpm dlx get-shit-done-cc@latest --claude --global --force-statusline", - // Clipboard support for wl-copy/wl-paste (used by CLAUDE.md) - "clipboard": "sudo apt-get update -qq && sudo apt-get install -y -qq --no-install-recommends wl-clipboard", - // Install vscode focus timer extension - "focus-timer": "d=~/focus-timer-ext && git clone --depth 1 https://github.com/phroi/vscode-focus-timer.git $d && ln -sfn $d ~/.vscode-server/extensions/phroi.focus" - }, - - // Run each time the container starts. Ensures updated dependencies are installed inside the container user environment. - "postStartCommand": "corepack use pnpm@latest && pnpm up", - - // Use the non-root 'node' user provided by the base image for safer file access and to mirror deployment permissions - "remoteUser": "node", - - "customizations": { - "vscode": { - "settings": { - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - "telemetry.enableTelemetry": false, - "telemetry.telemetryLevel": "off", - "chat.disableAIFeatures": true, - "claudeCode": { - "disableLoginPrompt": true, - "useTerminal": true - } - }, - - "extensions": [ - "streetsidesoftware.code-spell-checker", - "bradlc.vscode-tailwindcss", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "yoavbls.pretty-ts-errors", - "davidanson.vscode-markdownlint", - "anthropic.claude-code", - "-github.copilot-chat" // Disable GitHub Copilot Chat extension - ] - } - } -} diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index ac3749f..7b518c0 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -1,6 +1,9 @@ name: Check (lint, build and test) -on: [pull_request, push] +on: + pull_request: + push: + branches: [master] jobs: build: @@ -13,5 +16,8 @@ jobs: node-version: 24 - uses: pnpm/action-setup@v4 - - name: Check (lint, build and test) + - name: Install jq for fork bootstrap + run: sudo apt-get update -qq && sudo apt-get install -y -qq --no-install-recommends jq + + - name: Run pnpm check run: pnpm check diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml deleted file mode 100644 index 6f01729..0000000 --- a/.github/workflows/publish.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Release to NPM - -permissions: - pull-requests: write - contents: write - -on: - push: - branches: - - release - - "releases/**" - -concurrency: ${{ github.workflow }}-${{ github.ref }} - -jobs: - release: - name: Release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 24 - - uses: pnpm/action-setup@v4 - - - name: Install dependencies - run: pnpm install - - name: Build - run: pnpm build - - - name: Create Release Pull Request or Publish to npm - id: changesets - uses: changesets/action@v1 - with: - title: ${{ format('chore({0}){1} bump packages version', github.ref_name, ':') }} - commit: ${{ format('chore({0}){1} bump packages version', github.ref_name, ':') }} - version: pnpm run version - publish: pnpm changeset publish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 3aeab3f..0ae03a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,5 @@ # Dependencies **/node_modules/ -.pnpm-store/ # Artifacts **/dist/ - - -# AI tool config symlink -CLAUDE.md - -# Time tracking -.focus-timer diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md deleted file mode 100644 index e1222ed..0000000 --- a/.planning/PROJECT.md +++ /dev/null @@ -1,85 +0,0 @@ -# iCKB Stack v2 - -## What This Is - -A CCC-based TypeScript library suite and reference apps for interacting with the on-chain iCKB protocol (NervosDAO liquidity via pooled deposits and iCKB xUDT tokens). The library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) provide the building blocks; the apps (`bot`, `interface`, `faucet`, `sampler`, `tester`) demonstrate usage and run protocol operations. - -## Core Value - -Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts — no Lumos, no abandoned abstractions, no duplicated functionality with CCC. - -## Requirements - -### Validated - - - -- ✓ CCC-based package structure (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) — existing -- ✓ Manager pattern with `ScriptDeps` interface for composability — existing -- ✓ Async generator cell discovery with lazy evaluation — existing -- ✓ Molecule codec integration with CCC's `mol.union`, `ccc.Entity.Base`, `@ccc.codec` — existing -- ✓ Epoch class adopted from CCC (local Epoch deleted) — existing -- ✓ Faucet and sampler apps migrated to CCC — existing - -### Active - -- [ ] Remove SmartTransaction — replace with `ccc.Transaction` + utility functions -- [ ] Adopt CCC UDT handling — `IckbUdt extends udt.Udt` decided (Phase 3); managers get plain `ccc.Script` not `udt.Udt` instances (Phase 4); implementation in Phase 5 -- [ ] Systematic CCC alignment audit — replace local utilities with CCC equivalents from merged upstream PRs -- [ ] Migrate bot app from Lumos to CCC + new packages -- [ ] Migrate interface app from Lumos to CCC + new packages (straight swap, same UI) -- [ ] Migrate tester app from Lumos to CCC + new packages -- [ ] Remove all Lumos dependencies (`@ckb-lumos/*`, `@ickb/lumos-utils`, `@ickb/v1-core`) -- [ ] Clean APIs suitable for npm publication -- [ ] Identify reusable patterns that could become CCC upstream PRs -- [ ] Track CCC PR #328 (FeePayer) — potential CCC-native replacement for SmartTransaction's fee/balancing role - -### Out of Scope - -- UI/UX redesign for interface app — straight migration only -- New reference/example apps — existing apps serve as reference -- On-chain contract changes — contracts are immutable and non-upgradable -- Mobile app — web-first -- CCC framework changes — we adopt CCC, not fork it (PRs go upstream) - -## Context - -**Protocol:** iCKB tokenizes NervosDAO deposits. CKB deposited into NervosDAO is locked for ~30 days. iCKB represents that locked value as a liquid xUDT token. Key invariant: `Input UDT + Input Receipts = Output UDT + Input Deposits`. All contracts are deployed with zero-args locks (immutable, trustless). - -**iCKB UDT particularity:** iCKB value has three on-chain representations: (1) xUDT tokens (standard UDT), (2) receipt cells (pending conversion), (3) DAO deposit cells (locked CKB). CCC's `Udt` class only understands form (1). The relationship between all three forms is governed by the conservation law enforced by the `ickb_logic` type script. This makes CCC UDT adoption non-trivial — subclassing `Udt` to account for all three representations is a key design investigation. - -**SmartTransaction history:** `SmartTransaction` extends `ccc.Transaction` with UDT handler management and fee/change completion. The concept was proposed as an ecosystem-wide pattern but abandoned due to no adoption from CCC maintainers or other projects. The class itself still works and is used by all 5 library packages. Replacement: utility functions operating on plain `ccc.Transaction`. - -**CCC upstream contributions:** 12 PRs authored by this project's maintainer have been merged into CCC, covering: `shouldAddInputs` for completeFee (#225), `findCellsOnChain` (#258), auto capacity completion (#259), optimized completeFee (#260), UDT balance utilities (#228), multiple scripts for SignerCkbScriptReadonly (#265), `CellAny` type (#262), `reduce`/`reduceAsync` (#267), fixed-size mol union (#174), Epoch class (#314), UDT info querying (#261), `bytesLen`/`bytesLenUnsafe` (#353). PR #328 (FeePayer abstraction) is still open. - -**Local utility overlap with CCC core:** Several local utilities now have CCC equivalents that should be adopted: `gcd()`, `isHex()`, `hexFrom()`, `max()`/`min()` (use `numMax`/`numMin`). Utilities unique to iCKB (no CCC equivalent): `binarySearch()`, `asyncBinarySearch()`, `shuffle()`, `unique()`, `collect()`, `BufferedGenerator`, `MinHeap`. - -**Migration status:** Library packages are on CCC. Apps split: faucet/sampler already migrated; bot/interface/tester still on legacy Lumos (`@ckb-lumos/*`, `@ickb/lumos-utils@1.4.2`, `@ickb/v1-core@1.4.2`). - -**Local CCC dev build:** `forks/ccc/` supports using local CCC builds for testing. `.pnpmfile.cjs` transparently rewires `@ckb-ccc/*` to local packages. `forks/forker/patch.sh` rewrites exports to `.ts` source. This enables testing upstream changes before they're published. - -## Constraints - -- **On-chain contracts**: Immutable — library must match existing contract behavior exactly -- **CCC compatibility**: Must work with `@ckb-ccc/core ^1.12.2` (catalog-pinned) -- **Node.js**: >= 24 (enforced via engines) -- **Package manager**: pnpm 10.30.1 (pinned with SHA-512) -- **TypeScript**: Strict mode with `noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride` -- **Versioning**: All packages use `1001.0.0` (Epoch Semantic Versioning), managed by changesets -- **Publishing**: npm with `access: public` and `provenance: true` - -## Key Decisions - -| Decision | Rationale | Outcome | -|----------|-----------|---------| -| Remove SmartTransaction, use ccc.Transaction directly | SmartTransaction concept abandoned by ecosystem, no adoption from CCC maintainers | — Pending | -| Subclass CCC Udt for iCKB | iCKB value is multi-representation (xUDT + receipts + deposits); Phase 3 confirmed `IckbUdt extends udt.Udt` with `infoFrom` override is feasible and chosen | Decided (Phase 3) | -| IckbUdt uses individual code deps | CCC author dislikes dep groups for breaking semantics; IckbUdt overrides `addCellDeps` with xUDT + Logic code OutPoints; other managers keep dep groups for now | Decided (Phase 5 context) | -| Drop compressState, accept CCC errors | `completeInputsByBalance` replaces `completeUdt`; CCC's `ErrorUdtInsufficientCoin` replaces custom error class; callers format messages | Decided (Phase 5 context) | -| Managers get plain ccc.Script only | LogicManager/OwnedOwnerManager udtHandler removed (Phase 5), matching OrderManager pattern (Phase 4); udt.Udt instance lives at SDK level | Decided (Phase 5 context) | -| Library refactor before app migration | Clean packages first, then migrate apps on stable foundation | — Pending | -| Interface app: straight migration only | No UI/UX redesign — swap Lumos internals for CCC packages | — Pending | -| Track CCC PR #328 (FeePayer) | Could become CCC-native solution for what SmartTransaction does for fee completion | — Pending | - ---- -*Last updated: 2026-02-26 after Phase 5 context (code deps for IckbUdt, manager udtHandler removal, compressState dropped, CCC error adoption)* diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md deleted file mode 100644 index ba36c29..0000000 --- a/.planning/REQUIREMENTS.md +++ /dev/null @@ -1,112 +0,0 @@ -# Requirements: iCKB Stack v2 - -**Defined:** 2026-02-21 -**Core Value:** Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts -- no Lumos, no abandoned abstractions, no duplicated functionality with CCC. - -## v1 Requirements - -Requirements for initial milestone. Each maps to roadmap phases. - -### SmartTransaction Removal - -- [x] **SMTX-01**: All manager method signatures across all 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`, following CCC's convention (TransactionLike input, Transaction output); `CapacityManager` is deleted (not migrated) -- [x] **SMTX-02**: `SmartTransaction` class and its `completeFee()` override are deleted from `@ickb/utils` -- [ ] **SMTX-03**: Fee completion uses CCC-native `ccc.Transaction.completeFeeBy()` or `completeFeeChangeToLock()` with DAO-aware capacity calculation -- [x] **SMTX-04**: `getHeader()` function and `HeaderKey` type are removed from `@ickb/utils`; all call sites inline CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`); header caching handled transparently by `ccc.Client.cache` -- [x] **SMTX-05**: UDT handler registration (`addUdtHandlers()`) is replaced by direct `Udt` instance usage or standalone utility functions -- [x] **SMTX-06**: 64-output NervosDAO limit check is consolidated into a single utility function (currently scattered across 6 locations) -- [x] **SMTX-07**: `IckbUdtManager` multi-representation UDT balance logic (xUDT + receipts + deposits) survives removal intact -- conservation law `Input UDT + Input Receipts = Output UDT + Input Deposits` preserved via accurate balance reporting in `IckbUdt.infoFrom` (on-chain script is authoritative enforcer) -- [ ] **SMTX-08**: `IckbSdk.estimate()` and `IckbSdk.maturity()` continue working after SmartTransaction removal -- [ ] **SMTX-09**: All 5 library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) compile and pass type checking after removal -- [x] **SMTX-10**: Deprecated CCC API calls (`udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt`) are replaced with `@ckb-ccc/udt` equivalents - -### CCC Utility Deduplication - -- [x] **DEDUP-01**: Local `max()` / `min()` replaced across all packages -- `Math.max()`/`Math.min()` for number-typed contexts (avoids unnecessary `number→bigint→number` round-trips via `ccc.numMax()`) -- [x] **DEDUP-02**: Local `gcd()` replaced with `ccc.gcd()` across all packages -- [x] **DEDUP-03**: Local `isHex()` replaced with `ccc.isHex()` in `@ickb/utils` -- [x] **DEDUP-04**: Local `hexFrom()` refactored to explicit calls -- CCC's `hexFrom()` only handles `HexLike` (not `bigint | Entity`), so call sites should use `ccc.numToHex()` for bigint and `ccc.hexFrom(entity.toBytes())` for entities (per STACK.md evaluation) -- [x] **DEDUP-05**: iCKB-unique utilities (`binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`) are preserved unchanged - -### CCC Udt Integration - -- [x] **UDT-01**: Feasibility assessment completed: can `IckbUdt extends udt.Udt` override `infoFrom()` or `getInputsInfo()`/`getOutputsInfo()` to account for receipt cells and deposit cells alongside xUDT cells -- [x] **UDT-02**: Header access pattern for receipt value calculation is designed -- determine whether `client.getCellWithHeader()`, `client.getTransactionWithHeader()`, or direct CCC client calls are used within the Udt override (`getHeader()` utility removed in Phase 1) -- [x] **UDT-03**: Decision documented: subclass CCC `Udt` vs. keep custom `UdtHandler` interface vs. hybrid approach -- [x] **UDT-04**: `IckbUdt extends udt.Udt` implemented in `@ickb/core` with `infoFrom` override for multi-representation balance; individual code deps via overridden `addCellDeps`; `typeScriptFrom` static method; LogicManager/OwnedOwnerManager `udtHandler` removed -- [x] **UDT-05**: N/A -- Phase 3 confirmed subclassing IS viable (option a chosen) - -## v2 Requirements - -Deferred to next milestone. Tracked but not in current roadmap. - -### API & Publication - -- **API-01**: Clean public API surface -- audit all `export *` barrel files, mark internal symbols with `@internal` -- **API-02**: npm publication with provenance -- publish updated packages after API audit -- **API-03**: Type export audit -- ensure `.d.ts` correctness, no `any` leaks in public API - -### App Migration - -- **APP-01**: Bot app migrated from Lumos to CCC + new library packages -- **APP-02**: Interface app migrated from Lumos to CCC + new library packages (straight swap, same UI) -- **APP-03**: Tester app migrated from Lumos to CCC + new library packages - -### Ecosystem Cleanup - -- **CLEAN-01**: Complete Lumos removal -- remove all `@ckb-lumos/*`, `@ickb/lumos-utils`, `@ickb/v1-core` dependencies -- **CLEAN-02**: Upstream CCC contribution -- identify reusable patterns for CCC PRs - -## Out of Scope - -Explicitly excluded. Documented to prevent scope creep. - -| Feature | Reason | -|---------|--------| -| UI/UX redesign for interface app | Straight migration only -- conflates concerns, delays migration | -| New reference/example apps | Existing 5 apps already demonstrate all library capabilities | -| On-chain contract changes | All contracts deployed with zero-args locks (immutable, non-upgradable) | -| Mobile app | Web-first, web-only for now | -| CCC framework fork | We adopt CCC, not fork it -- PRs go upstream | -| Custom Molecule codec library | CCC already provides `mol.*` -- custom codecs duplicate effort | -| Custom blockchain indexer | CCC's `findCells`/`findCellsOnChain` covers all current needs | -| Multi-chain / L2 token bridging | Separate concern requiring different architecture | -| Embedded wallet/signer management | CCC provides comprehensive signer abstraction | -| Database/state persistence layer | All state is on-chain -- database creates stale-state problems | -| SmartTransaction as ecosystem standard | Abandoned by CCC maintainers and broader ecosystem | - -## Traceability - -Which phases cover which requirements. Updated during roadmap creation. - -| Requirement | Phase | Status | Notes | -|-------------|-------|--------|-------| -| SMTX-01 | Phase 1 | Complete | All signatures migrated to TransactionLike across all packages (01-03) | -| SMTX-02 | Phase 1 | Complete | SmartTransaction class deleted from @ickb/utils (01-03) | -| SMTX-03 | Phase 6 | Pending | | -| SMTX-04 | Phase 1 | Complete | getHeader()/HeaderKey removed, CCC client calls inlined | -| SMTX-05 | Phase 1, 4, 5 | In Progress | addUdtHandlers() replaced with tx.addCellDeps(udtHandler.cellDeps) (01-03); Phase 4: OrderManager.udtHandler→udtScript; Phase 5: LogicManager/OwnedOwnerManager.udtHandler removed + UdtHandler/UdtManager/ErrorTransactionInsufficientCoin/findUdts/UdtCell deleted from utils | -| SMTX-06 | Phase 1 | Complete | DAO check contributed to CCC core via forks/ccc/ (01-01) | -| SMTX-07 | Phase 5 | Complete | | -| SMTX-08 | Phase 6 | Pending | | -| SMTX-09 | Phase 7 | Pending | | -| SMTX-10 | Phase 5 | Complete | Deprecated ccc.udtBalanceFrom() calls are in utils (UdtManager) and core (IckbUdtManager), not dao/order. All replaced when UdtManager deleted and IckbUdt implemented in Phase 5 | -| DEDUP-01 | Phase 2 | Complete | max()/min() replaced with Math.max()/Math.min() for number-typed contexts, local deleted (02-01) | -| DEDUP-02 | Phase 2 | Complete | gcd() replaced with ccc.gcd(), local deleted (02-01) | -| DEDUP-03 | Phase 2 | Complete | isHex() deleted, only used internally by deleted hexFrom() (02-01) | -| DEDUP-04 | Phase 2 | Complete | hexFrom() call sites use entity.toHex() or ccc.hexFrom(), local deleted (02-01) | -| DEDUP-05 | Phase 2 | Complete | All 8 iCKB-unique utilities preserved unchanged (02-01) | -| UDT-01 | Phase 3 | Complete | | -| UDT-02 | Phase 3 | Complete | | -| UDT-03 | Phase 3 | Complete | | -| UDT-04 | Phase 5 | Complete | IckbUdt with infoFrom override, code deps, typeScriptFrom, manager cleanup | -| UDT-05 | Phase 3 | N/A | Subclassing confirmed viable — option (a) chosen | - -**Coverage:** -- v1 requirements: 20 total -- Mapped to phases: 20 -- Unmapped: 0 - ---- -*Requirements defined: 2026-02-21* -*Last updated: 2026-02-26 after Phase 5 context (UDT-05 N/A — subclassing viable; SMTX-05 expanded with LogicManager/OwnedOwnerManager cleanup; UDT-04 detailed with code deps, typeScriptFrom, manager cleanup)* diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md deleted file mode 100644 index 79373c3..0000000 --- a/.planning/ROADMAP.md +++ /dev/null @@ -1,149 +0,0 @@ -# Roadmap: iCKB Stack v2 - -## Overview - -This roadmap delivers the v1 milestone: removing the abandoned SmartTransaction abstraction, adopting CCC-native utilities and UDT patterns, and verifying the entire 5-package library suite compiles and functions against plain `ccc.Transaction`. Phase 1 uses a **feature-slice approach** — each removal is chased across all packages so the build stays green at every step, which front-loads method signature migration. Later phases handle UDT pattern finalization (after Phase 3 investigation), deprecated API replacement, SDK completion, and full verification. - -## Phases - -**Phase Numbering:** -- Integer phases (1, 2, 3): Planned milestone work -- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED) - -Decimal phases appear between their surrounding integers in numeric order. - -- [x] **Phase 1: SmartTransaction Removal (feature-slice)** - Delete SmartTransaction class and infrastructure across all packages; contribute 64-output DAO limit check to CCC core; migrate all method signatures to ccc.TransactionLike -- [x] **Phase 2: CCC Utility Adoption** - Replace local utility functions that duplicate CCC equivalents across all packages; preserve iCKB-unique utilities -- [x] **Phase 3: CCC Udt Integration Investigation** - Assess feasibility of subclassing CCC's Udt class for iCKB's multi-representation value; design header access pattern; document decision -- [x] **Phase 4: Deprecated CCC API Replacement** - Replace UdtHandler dependency in `@ickb/order` with plain `ccc.Script`; remove UDT cellDeps management from OrderManager; correct Phase 3 docs; verify `@ickb/dao` already clean -- [ ] **Phase 5: @ickb/core UDT Refactor** - Implement `IckbUdt extends udt.Udt` with `infoFrom` override; remove `udtHandler` from LogicManager/OwnedOwnerManager; delete UdtHandler/UdtManager/ErrorTransactionInsufficientCoin/findUdts from utils; adopt individual code deps for IckbUdt; update SDK construction and error handling -- [ ] **Phase 6: SDK Completion Pipeline** - Wire IckbSdk facade to CCC-native fee completion; verify estimate() and maturity() work end-to-end -- [ ] **Phase 7: Full Stack Verification** - Verify all 5 library packages compile clean with no SmartTransaction remnants and no type errors - -## Phase Details - -### Phase 1: SmartTransaction Removal (feature-slice) -**Goal**: SmartTransaction class, CapacityManager class are deleted; all manager method signatures across all 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`; 64-output DAO limit check is contributed to CCC core; `getHeader()`/`HeaderKey` are removed and inlined. Each removal is chased across all packages — build stays green at every step. -**Depends on**: Nothing (first phase) -**Requirements**: SMTX-01, SMTX-02, SMTX-04, SMTX-06 -**Success Criteria** (what must be TRUE): - 1. `SmartTransaction` class and `CapacityManager` class no longer exist in `@ickb/utils` source or exports - 2. `UdtHandler` interface and `UdtManager` class remain in `@ickb/utils` with method signatures updated from `SmartTransaction` to `ccc.TransactionLike` (full replacement deferred to Phase 3+) - 3. `getHeader()` function and `HeaderKey` type are removed from `@ickb/utils`; all call sites across dao/core/sdk inline CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`); `SmartTransaction.addHeaders()` call sites in DaoManager/LogicManager push to `tx.headerDeps` directly - 4. A 64-output NervosDAO limit check exists in CCC core (via `forks/ccc/`): `completeFee()` safety net, standalone async utility, and `ErrorNervosDaoOutputLimit` error class; all 6+ scattered checks across dao/core packages are replaced with calls to this CCC utility - 5. ALL manager method signatures across ALL 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`, following CCC's convention (TransactionLike input, Transaction output with `Transaction.from()` conversion at entry point) - 6. `pnpm check:full` passes after each feature-slice removal step — no intermediate broken states -**Plans**: 3 plans - -Plans: -- [x] 01-01-PLAN.md — Build CCC DAO utility (ErrorNervosDaoOutputLimit + assertDaoOutputLimit) and replace all 7 scattered DAO checks -- [x] 01-02-PLAN.md — Remove getHeader()/HeaderKey, inline CCC client calls at all call sites, replace addHeaders with headerDeps push -- [x] 01-03-PLAN.md — Delete SmartTransaction + CapacityManager, update all method signatures to TransactionLike, clean SDK - -### Phase 2: CCC Utility Adoption -**Goal**: Local utility functions that duplicate CCC core functionality are replaced with CCC equivalents across all packages; iCKB-unique utilities are explicitly preserved -**Depends on**: Phase 1 -**Requirements**: DEDUP-01, DEDUP-02, DEDUP-03, DEDUP-04, DEDUP-05 -**Success Criteria** (what must be TRUE): - 1. All call sites using local `max()`/`min()` now use `Math.max()`/`Math.min()` (number-typed contexts) and the local implementations are deleted - 2. All call sites using local `gcd()` now use `ccc.gcd()` and the local implementation is deleted - 3. Local `isHex()` in `@ickb/utils` is replaced with `ccc.isHex()` - 4. Local `hexFrom()` call sites are refactored to explicit calls: `ccc.numToHex()` for bigint and `ccc.hexFrom(entity.toBytes())` for entities (CCC's `hexFrom()` only handles `HexLike`, not `bigint | Entity`) - 5. iCKB-unique utilities (`binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`) remain in `@ickb/utils` unchanged -**Plans**: 1 plan - -Plans: -- [x] 02-01-PLAN.md — Replace local max/min/gcd/hexFrom/isHex with CCC equivalents, delete local implementations, preserve iCKB-unique utilities - -### Phase 3: CCC Udt Integration Investigation -**Goal**: Clear, documented decision on whether IckbUdt should extend CCC's `udt.Udt` class for iCKB's multi-representation value (xUDT + receipts + deposits), with the header access pattern designed. This decision determines the replacement for UdtHandler/UdtManager (which remain in `@ickb/utils` with updated signatures after Phase 1). -**Depends on**: Nothing (can proceed in parallel with Phases 1-2; design investigation, not code changes) -**Requirements**: UDT-01, UDT-02, UDT-03 -**Success Criteria** (what must be TRUE): - 1. A written feasibility assessment exists answering: can `IckbUdt extends udt.Udt` override `infoFrom()` (or `getInputsInfo()`/`getOutputsInfo()`) to account for receipt cells and deposit cells alongside xUDT cells, without breaking CCC's internal method chains - 2. The header access pattern for receipt value calculation is designed and documented -- specifying whether `client.getCellWithHeader()`, `client.getTransactionWithHeader()`, or direct CCC client calls are used within the Udt override (note: `getHeader()` was removed in Phase 1) - 3. A decision document exists with one of three outcomes: (a) subclass CCC Udt, (b) keep custom interface, (c) hybrid approach -- with rationale for the chosen path -**Plans**: 2 plans - -Plans: -- [x] 03-01-PLAN.md — Trace CCC Udt internals end-to-end, verify infoFrom override feasibility, resolve open questions -- [x] 03-02-PLAN.md — Write formal decision document (feasibility assessment, header access pattern, decision with rationale) - -### Phase 4: Deprecated CCC API Replacement -**Goal**: `UdtHandler` dependency in `@ickb/order` is replaced with plain `ccc.Script` (`udtScript`); UDT cellDeps management removed from OrderManager (caller/CCC Udt handles externally during balance completion); `@ickb/dao` verified clean (no UdtHandler, no deprecated APIs); Phase 3 decision doc corrected to match actual codebase state -**Depends on**: Phase 1 (signatures migrated), Phase 3 (UDT decision) -**Requirements**: SMTX-05 -**Success Criteria** (what must be TRUE): - 1. `OrderManager` constructor accepts `udtScript: ccc.Script` instead of `udtHandler: UdtHandler` -- all 9 `this.udtHandler.script` references replaced with `this.udtScript` - 2. All `tx.addCellDeps(this.udtHandler.cellDeps)` calls removed from `mint()`, `addMatch()`, `melt()` -- UDT cellDeps are caller responsibility - 3. `@ickb/order` no longer imports `UdtHandler` from `@ickb/utils`; no new `@ckb-ccc/udt` dependency added - 4. `@ickb/dao` has no UdtHandler references and no deprecated CCC API calls (verified, no changes needed) - 5. Phase 3 decision doc `03-DECISION.md` "Implementation Guidance for Phase 4" section corrected - 6. `pnpm check:full` passes -**Plans**: 1 plan - -Plans: -- [x] 04-01-PLAN.md — Replace OrderManager udtHandler with udtScript: ccc.Script, remove UDT cellDeps, update SDK caller, verify dao and decision doc clean - -### Phase 5: @ickb/core UDT Refactor -**Goal**: `IckbUdt extends udt.Udt` implemented in `@ickb/core` with `infoFrom` override for multi-representation balance; iCKB conservation law preserved via accurate balance reporting; `udtHandler` removed from LogicManager/OwnedOwnerManager (Phase 4 pattern); `UdtHandler`, `UdtManager`, `ErrorTransactionInsufficientCoin`, `UdtCell`, `findUdts`, `addUdts` deleted from `@ickb/utils`; IckbUdt uses individual code deps (not dep group) with overridden `addCellDeps`; SDK updated to construct `IckbUdt` and handle CCC's `ErrorUdtInsufficientCoin`. See `05-CONTEXT.md` for full decisions. -**Depends on**: Phase 3 (UDT decision), Phase 4 (order UDT pattern finalized) -**Requirements**: SMTX-05, SMTX-07, SMTX-10, UDT-04 -**Success Criteria** (what must be TRUE): - 1. `IckbUdt extends udt.Udt` exists in `@ickb/core` with overridden `infoFrom()` that accurately values xUDT cells (positive), receipt cells (positive, input only), and deposit cells (negative, input only) -- conservation law preserved via correct sign conventions - 2. `IckbUdt.addCellDeps` overridden to add individual code deps (xUDT code OutPoint + iCKB Logic code OutPoint) instead of dep group - 3. `IckbUdtManager.calculateScript` renamed to `IckbUdt.typeScriptFrom` (static, same params) - 4. `LogicManager` and `OwnedOwnerManager` no longer take `udtHandler` parameter; `tx.addCellDeps(this.udtHandler.cellDeps)` calls removed (4 sites) -- UDT cellDeps are caller responsibility (Phase 4 pattern) - 5. `UdtHandler` interface, `UdtManager` class, `ErrorTransactionInsufficientCoin` class, `UdtCell` interface, `findUdts`, `addUdts`, `isUdtSymbol` deleted from `@ickb/utils` - 6. No calls to deprecated CCC APIs (`ccc.udtBalanceFrom`) exist in `@ickb/core` or `@ickb/utils` - 7. SDK constructs `IckbUdt` instead of `IckbUdtManager`; passes `ickbUdt.script` to managers; handles `ErrorUdtInsufficientCoin` from CCC (not old `ErrorTransactionInsufficientCoin`) - 8. `pnpm check:full` passes -**Plans**: 2 plans - -Plans: -- [ ] 05-01-PLAN.md — Implement IckbUdt extends udt.Udt in core (infoFrom, addCellDeps, typeScriptFrom); remove udtHandler from LogicManager/OwnedOwnerManager; add @ckb-ccc/udt dependency -- [ ] 05-02-PLAN.md — Delete UDT infrastructure from utils (UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts); update SDK to construct IckbUdt with code OutPoints; verify pnpm check:full - -### Phase 6: SDK Completion Pipeline -**Goal**: IckbSdk facade uses CCC-native fee completion pipeline; estimate() and maturity() continue working after SmartTransaction removal -**Depends on**: Phase 5 (core refactored) -**Requirements**: SMTX-03, SMTX-08 -**Success Criteria** (what must be TRUE): - 1. `IckbSdk` transaction building uses `ccc.Transaction.completeFeeBy()` or `completeFeeChangeToLock()` for fee completion, with DAO-aware capacity calculation (no SmartTransaction.completeFee override) - 2. `IckbSdk.estimate()` returns correct iCKB exchange rate estimates when called against the refactored library - 3. `IckbSdk.maturity()` returns correct deposit maturity information when called against the refactored library - 4. The explicit completion pipeline ordering is correct: UDT completion before CKB capacity completion before fee completion -**Plans**: TBD - -Plans: -- [ ] 06-01: TBD -- [ ] 06-02: TBD - -### Phase 7: Full Stack Verification -**Goal**: All 5 library packages compile clean with strict TypeScript settings, no SmartTransaction remnants, and no deprecated CCC API calls anywhere in the codebase -**Depends on**: Phase 6 (SDK done -- all packages now updated) -**Requirements**: SMTX-09 -**Success Criteria** (what must be TRUE): - 1. `pnpm check:full` passes -- all 5 library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) compile with zero type errors under strict TypeScript settings (`noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride`) - 2. No imports of `SmartTransaction` exist anywhere in the codebase (library packages or apps) - 3. No calls to deprecated CCC APIs (`udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt`) exist anywhere in the 5 library packages -**Plans**: TBD - -Plans: -- [ ] 07-01: TBD - -## Progress - -**Execution Order:** -Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -(Note: Phase 3 could start in parallel with Phases 1-2; Phase 4 now depends on Phase 3 in addition to Phase 1) - -| Phase | Plans Complete | Status | Completed | -|-------|----------------|--------|-----------| -| 1. SmartTransaction Removal (feature-slice) | 3/3 | Complete | 2026-02-22 | -| 2. CCC Utility Adoption | 1/1 | Complete | 2026-02-23 | -| 3. CCC Udt Integration Investigation | 2/2 | Complete | 2026-02-24 | -| 4. Deprecated CCC API Replacement | 1/1 | Complete | 2026-02-26 | -| 5. @ickb/core UDT Refactor | 0/2 | Not started | - | -| 6. SDK Completion Pipeline | 0/2 | Not started | - | -| 7. Full Stack Verification | 0/1 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md deleted file mode 100644 index 1a8a8d3..0000000 --- a/.planning/STATE.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -gsd_state_version: 1.0 -milestone: v1.0 -milestone_name: milestone -status: unknown -last_updated: "2026-02-26T16:31:09.127Z" -progress: - total_phases: 5 - completed_phases: 5 - total_plans: 9 - completed_plans: 9 ---- - -# Project State - -## Project Reference - -See: .planning/PROJECT.md (updated 2026-02-20) - -**Core value:** Clean, CCC-aligned library packages published to npm that frontends can depend on to interact with iCKB contracts -- no Lumos, no abandoned abstractions, no duplicated functionality with CCC. -**Current focus:** Phase 5: @ickb/core UDT Refactor - -## Current Position - -Phase: 5 of 7 (@ickb/core UDT Refactor) -- Complete -Plan: 2 of 2 in current phase (all complete) -Status: Phase 5 complete -- all UDT infrastructure deleted, SDK rewired -Last activity: 2026-02-26 -- Completed 05-02-PLAN.md (delete UDT infra + wire SDK) - -Progress: [██████████] 100% - -## Performance Metrics - -**Velocity:** -- Total plans completed: 9 -- Average duration: ~10min -- Total execution time: 1.5 hours - -**By Phase:** - -| Phase | Plans | Total | Avg/Plan | -|-------|-------|-------|----------| -| 01 | 3/3 | 52min | 17min | -| 02 | 1/1 | 7min | 7min | -| 03 | 2/2 | 9min | 4.5min | -| 04 | 1/1 | 4min | 4min | -| 05 | 2/2 | 11min | 5.5min | - -**Recent Trend:** -- Last 5 plans: 03-02 (~4min), 04-01 (~4min), 05-01 (~7min), 05-02 (~4min) -- Trend: stable at ~5min per plan - -*Updated after each plan completion* - -## Accumulated Context - -### Decisions - -Decisions are logged in PROJECT.md Key Decisions table. -Recent decisions affecting current work: - -- [Roadmap]: Phase 1 uses feature-slice approach -- each removal chased across all packages, build stays green after every step. SMTX-01 (all signatures to TransactionLike) completed in Phase 1, not Phase 5. -- [Roadmap]: UDT investigation (Phase 3) is a design phase that produces a decision document; its outcome determines UdtHandler/UdtManager replacement pattern used in Phases 4-5 -- [Roadmap]: Phases 4-5 reduced in scope: Phase 4 focuses on deprecated API replacement + UDT pattern finalization in dao/order; Phase 5 focuses on IckbUdt implementation + conservation law in core -- [Phase 1 Context]: DAO 64-output limit check contributed to CCC core via forks/ccc/, CCC PR submitted during Phase 1 -- [Phase 1 Context]: getHeader()/HeaderKey removed entirely -- inline CCC client calls at read-only call sites; addHeaders() call sites in DaoManager/LogicManager push to tx.headerDeps directly -- [Phase 1 Context]: Script comparison must always use full Script.eq(), never just codeHash comparison -- [01-01]: Added forks/ccc local patch mechanism for deterministic replay of CCC modifications (now multi-file format: manifest + res-N.resolution + local-*.patch) -- [01-01]: DaoManager.requestWithdrawal/withdraw client parameter placed before optional options for cleaner API -- [01-01]: assertDaoOutputLimit uses early return when outputs <= 64 for zero-cost common case -- [01-02]: Moved getHeader/HeaderKey to transaction.ts as non-exported internals (deleted alongside SmartTransaction in 01-03) -- [01-02]: TransactionHeader moved to utils.ts as canonical location for downstream consumers -- [01-02]: Inlined CCC client calls use explicit null checks with descriptive error messages -- [01-03]: All manager methods accept ccc.TransactionLike and return ccc.Transaction (TransactionLike pattern) -- [01-03]: Replaced addUdtHandlers with tx.addCellDeps(this.udtHandler.cellDeps) across all packages -- [01-03]: SmartTransaction class and CapacityManager class fully deleted from @ickb/utils -- [01-03]: SDK getCkb() uses direct client.findCellsOnChain instead of CapacityManager -- [02-01]: Used Math.max() over Number(ccc.numMax()) for number-typed contexts to avoid unnecessary number→bigint→number round-trips -- [02-01]: Used entity.toHex() for Entity args, ccc.hexFrom() for BytesLike args -- matching CCC's type-safe separation -- [03-01]: infoFrom is the sole override point for IckbUdt -- no need to override getInputsInfo/getOutputsInfo -- [03-01]: No upstream CCC changes required for IckbUdt subclass -- all override points are public with appropriate signatures -- [03-01]: Caller responsibility for receipt/deposit cell discovery (not IckbUdt's filter) -- LogicManager/OwnedOwnerManager handle this -- [03-01]: Accurate balance reporting only -- conservation law enforcement is separate from infoFrom -- [03-02]: Decision: subclass CCC Udt (option a) -- IckbUdt extends udt.Udt with infoFrom override -- [03-02]: Conservation law: accurate balance reporting only; on-chain script is authoritative enforcer; build-time validation optional later -- [03-02]: Cell discovery boundary: infoFrom values cells already in transaction; callers (LogicManager/OwnedOwnerManager) find and add receipt/deposit cells -- [03-02]: UdtHandler interface and UdtManager class to be deleted in Phase 5, replaced by udt.Udt type -- [04-context]: DaoManager never had UdtHandler parameter -- @ickb/dao has no UDT-related code, no changes needed in Phase 4 -- [04-context]: OrderManager gets udtScript: ccc.Script (not udt.Udt) -- simpler pattern than Phase 3 anticipated -- [04-context]: UDT cellDeps removed from OrderManager -- caller/CCC Udt manages externally during balance completion -- [04-context]: No deprecated CCC API calls in dao or order packages -- those calls (ccc.udtBalanceFrom) are in utils (UdtManager) and core (IckbUdtManager), handled in Phase 5 -- [04-context]: Pattern established: managers receive plain ccc.Script for UDT type identification; udt.Udt instance lives at SDK/caller level -- [04-context]: Phase 3 decision doc corrected (DaoManager row removed, OrderManager updated, Phase 4 guidance rewritten) -- [04-01]: OrderManager receives ccc.Script (not udt.Udt) -- simpler than Phase 3 anticipated -- [04-01]: UDT cellDeps are caller responsibility -- documented via JSDoc @remarks on mint/addMatch/melt -- [05-context]: IckbUdt uses individual code deps (xUDT + Logic OutPoints), not dep group -- CCC author dislikes dep groups for breaking semantics -- [05-context]: Override addCellDeps on IckbUdt to add both code deps; other managers keep dep groups for now (mixed coexistence OK) -- [05-context]: Drop compressState feature -- CCC completeInputsByBalance handles completion; no wrapper needed -- [05-context]: Accept CCC's ErrorUdtInsufficientCoin; delete ErrorTransactionInsufficientCoin from utils; callers format messages -- [05-context]: Delete findUdts/addUdts/UdtCell/isUdtSymbol -- all internal to UdtManager, no external consumers -- [05-context]: LogicManager/OwnedOwnerManager: remove udtHandler param + cellDeps calls (Phase 4 pattern); UdtHandler interface has zero consumers → delete -- [05-context]: calculateScript renamed to IckbUdt.typeScriptFrom (static, same params) -- [05-context]: ValueComponents kept as-is for Phase 5; redesign deferred (ambiguous naming in multi-UDT context) -- [05-context]: Phase 5 handles SDK error handling updates (not deferred to Phase 6) -- [05-context]: CCC isUdt length check (>=16 bytes) equivalent to old >=34 hex chars -- no iCKB-specific reason for old threshold -- [05-context]: Matching bot infoFrom caching concern noted for researcher -- CCC Client.cache handles header dedup -- [05-01]: IckbUdt.infoFrom handles three cell types: xUDT (positive), receipt (positive via ickbValue), deposit (negative via ickbValue) -- [05-01]: addCellDeps adds individual code deps (xUDT + Logic OutPoints), not dep group -- [05-01]: CellAny cast to Cell for daoManager.isDeposit is safe: input cells are Cell instances, output cells gated by !cell.outPoint check -- [05-02]: IckbUdt.typeScriptFrom computes type script dynamically from raw UDT and Logic scripts (not hardcoded) -- [05-02]: Devnet code OutPoints fallback to cellDeps[0].outPoint -- pragmatic since devnet deps are typically depType: code -- [05-02]: ErrorTransactionInsufficientCoin had zero catch blocks across entire codebase -- clean deletion with no migration - -### Pending Todos - -None yet. - -### Blockers/Concerns - -- Resolved: CCC's `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` (verified in STACK.md from CCC source). No standalone utility needed. -- Resolved: CCC Udt `getInputsInfo()` resolves inputs to `Cell` objects (which have `outPoint`) before passing to `infoFrom()`. `infoFrom()`'s `CellAnyLike` parameter has `outPoint?: OutPointLike | null` — optional, not absent. Input cells have outPoint (for header fetches), output cells don't. Both `infoFrom` and `getInputsInfo/getOutputsInfo` are viable override points for IckbUdt (verified during Phase 3 discuss-phase). -- Resolved: STACK.md research correction applied — `client.getHeaderByTxHash()` (non-existent) replaced with `client.getTransactionWithHeader()` in STACK.md, ROADMAP.md Phase 3 success criterion #2, and REQUIREMENTS.md UDT-02. -- Resolved: PR #328 stance updated during Phase 3 context — user decision is to design around PR #328 as target architecture (overrides research recommendation to "not wait for #328"). PR #328 is now integrated into `forks/ccc/` via pins; FeePayer classes available at `forks/ccc/packages/core/src/signer/feePayer/`. The separate ccc-fee-payer reference clone is no longer needed. -- Resolved: `CellAny` has `capacityFree` getter (CCC transaction.ts:404-405) — 03-RESEARCH.md corrected (previously claimed `CellAny` lacked it). - -## Session Continuity - -Last session: 2026-02-26 -Stopped at: Completed 05-02-PLAN.md -- Phase 5 complete -Resume file: N/A (all phases complete) -Next action: PR preparation or Phase 6 planning diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md deleted file mode 100644 index c2c375d..0000000 --- a/.planning/codebase/ARCHITECTURE.md +++ /dev/null @@ -1,382 +0,0 @@ -# Architecture - -**Analysis Date:** 2026-02-17 - -## Pattern Overview - -**Overall:** Layered monorepo with blockchain-centric manager composition pattern - -**Key Characteristics:** -- Modular library packages (`packages/`) composed into high-level SDK -- Manager-based pattern encapsulating script operations with uniform `ScriptDeps` interface -- Async-first cell discovery via generator functions with lazy evaluation -- TypeScript ESM modules with strict null checks and type safety -- CCC-native transaction building with TransactionLike pattern (SmartTransaction deleted in Phase 1) -- Cell wrapper abstractions extending raw blockchain data with domain logic - -**Migration Status:** -- `packages/` contain the NEW replacement libraries built on CCC -- `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2` are LEGACY & DEPRECATED (this monorepo builds their replacements) -- All `@ckb-lumos/*` packages are DEPRECATED (CCC is the replacement) -- Apps split: `faucet` and `sampler` already use new packages; `bot`, `tester`, `interface` still on legacy Lumos -- CCC PRs for UDT and Epoch support have been MERGED upstream -- local Epoch class has been deleted (replaced by `ccc.Epoch`); some local UDT handling may still overlap with CCC's `@ckb-ccc/udt` -- Custom `mol.union` codec and deprecated `mol.*` APIs have been replaced with CCC's `mol.union`, `ccc.Entity.Base`, and `@ccc.codec` decorator -- SmartTransaction was DELETED in Phase 1; all managers now accept `ccc.TransactionLike` and return `ccc.Transaction` directly; headers cached by CCC Client Cache - -## Protocol Design (from whitepaper) - -The iCKB protocol solves NervosDAO illiquidity by pooling DAO deposits and issuing a liquid iCKB token. Key design principles: - -**Core Concept:** CKB deposited into NervosDAO is locked for ~30 days (180 epochs). iCKB tokenizes these deposits so users can trade the locked value immediately while still accruing DAO interest. - -**Exchange Rate:** `iCKB_value = unoccupied_capacity * AR_0 / AR_m` where `AR_0 = 10^16` (genesis accumulated rate) and `AR_m` is the accumulated rate at the deposit block. CKB is inflationary; iCKB is not -- 1 iCKB represents an ever-increasing amount of CKB over time. - -**Deposit (2-Step):** -1. Step 1: User deposits CKB into NervosDAO -> receives a Receipt cell (cannot calculate iCKB value yet because the block's accumulated rate isn't available during validation). -2. Step 2: Receipt cell is converted to iCKB xUDT tokens using the now-available accumulated rate from the deposit block header. - -**Withdrawal (2-Step):** -1. Step 1: User burns iCKB tokens -> creates a NervosDAO withdrawal request (using any mature deposit from the pool, not necessarily the user's original deposit). -2. Step 2: Standard NervosDAO withdrawal after 180-epoch maturity. - -**Soft Cap Penalty:** Deposits exceeding 100,000 iCKB-equivalent incur a 10% discount on the excess amount. This incentivizes standard-size deposits (~100k CKB) and prevents DoS via fragmentation. Formula: `final = amount - (amount - 100000) / 10` when `amount > 100000`. - -**Pooled Deposits:** Unlike dCKB (predecessor), deposits are protocol-owned, not user-specific. Any mature deposit can satisfy any withdrawal request. This eliminates the "original depositor only" restriction. - -**Non-Upgradable:** All scripts are deployed with zero-args locks (unlockable), making the protocol immutable and trustless. No governance, no oracles, no admin keys. - -## On-Chain Contracts (Rust) - -Three production smart contracts (in `forks/contracts/` reference repo) implement the protocol on CKB L1. Each TS package in `packages/` corresponds to contract logic: - -| Contract | Script Type | TS Package | Purpose | -|---|---|---|---| -| `ickb_logic` | Type script | `@ickb/core` (LogicManager) | Controls iCKB minting/burning, validates deposits and receipts, enforces conservation law | -| `limit_order` | Lock script | `@ickb/order` (OrderManager) | Enables peer-to-peer limit order matching for CKB/UDT trading | -| `owned_owner` | Lock script | `@ickb/core` (OwnedOwnerManager) | Manages owner-owned cell pairing for DAO withdrawal delegation | -| (shared `utils`) | Library | `@ickb/utils`, `@ickb/dao` | DAO helpers, safe math (C256), MetaPoint, cell type classification | - -**Key Contract Invariant (ickb_logic):** -``` -Input UDT + Input Receipts = Output UDT + Input Deposits -``` -Receipts convert to UDT; deposits stay as deposits or convert to UDT. No iCKB can be created or destroyed outside this conservation law. - -**Limit Order Lifecycle:** Mint (create order + master cell) -> Match (partial/full fill preserving value) -> Melt (destroy fulfilled order). Value conservation: `in_ckb * ckb_mul + in_udt * udt_mul <= out_ckb * ckb_mul + out_udt * udt_mul`. - -**Owned Owner Pairing:** 1:1 relationship between "owned" cells (DAO withdrawal requests) and "owner" cells (authorization). Connected via relative `owned_distance: i32` offset. Solves NervosDAO's constraint that deposit lock and withdrawal lock must have equal size. - -## Layers - -**Foundation: CCC Framework** -- Purpose: Provide blockchain primitives and client interface -- Location: `@ckb-ccc/core` (npm or local `forks/ccc/`) -- Contains: CKB RPC clients, transaction builders, signers, Molecule codec, UDT support, Epoch handling -- Used by: All packages and applications -- Note: CCC now includes UDT and Epoch features contributed by this project's maintainer - -**Utilities Layer (`packages/utils/src/`)** -- Purpose: Reusable blockchain primitives and UDT handlers -- Key exports: `UdtManager`, `UdtHandler`, codec/heap utilities -- Key files: - - `udt.ts` (407 lines): UDT token value calculations and handlers - - `utils.ts` (292 lines): General utilities (binary search, collectors, helpers) - - `codec.ts` (21 lines): CheckedInt32LE codec - - `heap.ts` (175 lines): MinHeap implementation -- Depends on: `@ckb-ccc/core` -- Used by: All domain packages -- Note: `SmartTransaction`, `CapacityManager`, `transaction.ts`, `capacity.ts` were deleted in Phase 1 - -**Domain Layer - DAO (`packages/dao/src/`)** -- Purpose: Abstract Nervos DAO operations (deposit, withdraw, requestWithdrawal) -- Key abstractions: - - `DaoManager`: Implements ScriptDeps, manages deposit/withdrawal transactions - - `DaoCell`: Wraps blockchain cell with maturity and interest calculations - - Methods: `isDeposit()`, `isWithdrawalRequest()`, async generators `findDeposits()` and `findWithdrawalRequests()` -- Key files: - - `dao.ts` (412 lines): DaoManager implementation - - `cells.ts` (180 lines): DaoCell construction and type checking -- Depends on: Utilities layer -- Used by: Core and applications - -**Domain Layer - Order (`packages/order/src/`)** -- Purpose: Limit order cell management and matching logic -- Key abstractions: - - `OrderManager`: Implements ScriptDeps, mint/satisfy/melt operations - - `OrderCell`, `MasterCell`, `OrderGroup`: Order representation and grouping - - `Info`, `Ratio`: Order metadata and exchange ratio types - - Conversion logic with fee calculations (default 0.001% fee) -- Key files: - - `order.ts` (988 lines): OrderManager with convert/mint/satisfy/melt/find methods - - `entities.ts` (754 lines): Info/Ratio/OrderData types and comparisons - - `cells.ts` (396 lines): Cell wrappers for orders, groups, masters -- Depends on: Utilities layer -- Used by: Core and SDK - -**Domain Layer - Core iCKB Logic (`packages/core/src/`)** -- Purpose: iCKB protocol-specific operations (deposits, receipts, ownership) -- Key abstractions: - - `LogicManager`: Deposit/receipt management (implements ScriptDeps) - - `OwnedOwnerManager`: Ownership and withdrawal group management (implements ScriptDeps) - - `IckbDepositCell`: DAO cell marked as iCKB deposit - - `ReceiptCell`, `WithdrawalGroup`, `OwnerCell`: Domain-specific cell types -- Key files: - - `logic.ts` (269 lines): LogicManager for deposits and receipts - - `owned_owner.ts` (239 lines): OwnedOwnerManager for withdrawal operations - - `cells.ts` (175 lines): Cell wrappers and type constructors - - `udt.ts` (213 lines): iCKB UDT calculations -- Depends on: DAO + Utilities layers -- Used by: SDK - -**SDK Composition Layer (`packages/sdk/src/`)** -- Purpose: High-level interface composing all domain managers -- Key abstractions: - - `IckbSdk`: Factory and orchestrator class - - `SystemState`: Immutable snapshot of blockchain state (fee rate, tip, exchange ratio, orders, available/maturing CKB) - - `CkbCumulative`: Maturing CKB entries with cumulative amounts -- Key methods: - - Static `estimate()`: Conversion preview with optional fee - - Static `maturity()`: Estimated order fulfillment timestamp - - Instance `request()`: Create order cell - - Instance `collect()`: Cancel order groups - - Instance `getL1State()`: Fetch complete system state - - Instance `getCkb()` (private): Maturing CKB calculation from deposits and bot withdrawals -- Key files: - - `sdk.ts` (512 lines): IckbSdk implementation - - `constants.ts` (205 lines): Script configurations - - `codec.ts` (138 lines): Pool snapshot encoding/decoding -- Depends on: All domain + utils layers -- Used by: Applications - -**Application Layer (`apps/*/src/`)** -- Purpose: Domain-specific operational services - - **Faucet (Migrated to CCC + New Packages):** - - Location: `apps/faucet/src/main.ts` (88 lines), entry via `apps/faucet/src/index.ts` - - Entry: `main()` async function - - Pattern: Infinite loop with 2-minute poll interval - - Uses: CCC client, ccc.Transaction - - Flow: Discover faucet funds → transfer to user account → log JSON results - - **Sampler (Migrated to CCC):** - - Location: `apps/sampler/src/index.ts` (192 lines) - - Entry: Direct execution - - Pattern: Periodic blockchain observation - - Uses: CCC primitives - - **Bot (Legacy - Lumos):** - - Location: `apps/bot/src/index.ts` (897 lines) - - Entry: `main()` async function - - Pattern: Infinite loop with configurable sleep interval - - Uses: `@ickb/v1-core`, `@ckb-lumos/*`, TransactionSkeleton - - Flow: Query orders → match at midpoint → build transaction → sign/broadcast - - Note: Status quo legacy implementation; NOT yet migrated - - **Interface (Legacy - Lumos + React):** - - Location: `apps/interface/src/` (total 1,158 lines) - - Entry: `startApp(wallet_chain)` in `main.tsx` (68 lines) - - Pattern: React component hierarchy with React Query state management - - Uses: `@ickb/v1-core`, `@ckb-lumos/*`, React, TanStack Query - - Component tree: - - `Connector.tsx` (104 lines): Wallet connection setup - - `App.tsx` (93 lines): Main state/conversion logic - - `Form.tsx` (144 lines): Input form - - `Action.tsx` (174 lines): Transaction execution - - `Dashboard.tsx` (36 lines): Balance display - - `Progress.tsx` (42 lines): Loading indicator - - Queries/Utils: `queries.ts` (395 lines), `transaction.ts` (291 lines), `utils.ts` (160 lines) - - Note: Status quo legacy implementation; NOT yet migrated - - **Tester (Legacy - Lumos):** - - Location: `apps/tester/src/index.ts` (469 lines) - - Entry: `main()` async function - - Pattern: Simulation of order creation scenarios - - Uses: `@ickb/v1-core`, `@ckb-lumos/*` - -## Data Flow - -**Order Creation and Matching (Primary Flow):** - -1. User calls `IckbSdk.request(tx, user, info, amounts)` via app -2. `OrderManager.mint()` creates order cell with `Info` metadata (ratio, direction, fee info) -3. Transaction adds cell deps, outputs via `tx.addCellDeps()` / `tx.addOutput()` -4. User signs and broadcasts transaction - -**Order Discovery and Matching (Bot Flow):** - -1. Bot calls `IckbSdk.getL1State(client, locks)` -2. Parallel fetch: tip header, fee rate, order cells, bot capacities -3. Calculate exchange ratio from tip: `Ratio.from(ickbExchangeRatio(tip))` -4. Fetch deposits and withdrawal requests to calculate maturing CKB -5. Filter orders: separate user orders from system-matchable orders (ratio within 0.1% of midpoint) -6. Estimate maturity for each user order based on pool liquidity -7. Returns `SystemState { feeRate, tip, exchangeRatio, orderPool, ckbAvailable, ckbMaturing }` -8. Bot identifies orders where CKB/UDT supply exists for matching -9. Calls `OrderManager.satisfy()` to process matched orders -10. Builds transaction with satisfied order cells and input/output witnesses -11. Completes fees via `tx.completeFeeChangeToLock()` -12. Signs and broadcasts - -**Maturity Estimation (Supporting Calculation):** - -1. `IckbSdk.maturity(order, system)` computes estimated fulfillment timestamp -2. For dual-ratio orders: returns undefined (no fixed maturity) -3. For single-direction orders: - - Scans order pool to calculate available opposite liquidity - - Applies exchange ratio conversion to matching depth - - If sufficient liquidity exists: maturity = 10 minutes + (amount / capacity scaling factor) - - If insufficient: finds earliest bin in `ckbMaturing` cumulative array that covers shortfall -4. Returns Unix timestamp (milliseconds) or undefined - -**Conversion Preview (UI Flow):** - -1. User calls `IckbSdk.estimate(isCkb2Udt, amounts, system, options?)` -2. Applies 0.001% default fee (or custom fee/feeBase) -3. Calls `OrderManager.convert()` with adjusted ratio -4. Returns `{ convertedAmount, ckbFee, info, maturity? }` -5. UI displays converted amount and estimated maturity if applicable - -**Deposit Lifecycle:** - -1. User calls `LogicManager.deposit()` to lock CKB in Nervos DAO -2. Receipt cell minted containing deposit metadata -3. Bot fetches deposits via `LogicManager.findDeposits()` -4. After maturity, bot calls `LogicManager.withdraw()` to extract funds -5. Change cells added via CCC fee completion pipeline - -**State Management:** - -- L1 state: Immutable snapshots fetched per query with configurable refresh intervals -- Transaction state: Built incrementally via `ccc.Transaction` methods (`addInput`, `addOutput`, `addCellDeps`) -- UDT balances: Tracked via `UdtHandler` interface implementations -- Maturing CKB: Cumulative array sorted by maturity timestamp - -## Key Abstractions - -**ScriptDeps Interface (Contracts):** -- Implemented by: DaoManager, OrderManager, LogicManager, OwnedOwnerManager -- Contract: `{ script: ccc.Script; cellDeps: ccc.CellDep[] }` -- Purpose: Uniform interface for adding script dependencies to transactions -- Pattern: Enables composability and type-safe manager stacking - -**Manager Classes (Pattern):** -- Purpose: Encapsulate entity-specific operations -- Pattern: Stateless managers with methods that accept `ccc.TransactionLike` and return `ccc.Transaction` -- Examples: - - `DaoManager.deposit(tx, capacities, lock)`: Add DAO deposit cells - - `OrderManager.mint(tx, user, info, amounts)`: Create order cell - - `LogicManager.deposit(tx, user, info, amounts)`: Create iCKB deposit with receipt -- Type checkers: `isDeposit()`, `isOrder()`, `isMaster()` methods for cell filtering - -**Cell Wrappers (Abstraction):** -- Purpose: Extend raw blockchain cells with domain calculations -- Pattern: Factory functions return wrapped interfaces with computed properties -- Examples: - - `DaoCell`: Adds maturity, interests, isReady properties - - `IckbDepositCell`: Extends DaoCell with [isIckbDepositSymbol] marker - - `ReceiptCell`: Wraps receipt data with header reference - - `WithdrawalGroup`: Pairs owned (withdrawal request) + owner cell with value aggregation -- Construction: Async factories via `daoCellFrom()`, `ickbDepositCellFrom()`, `receiptCellFrom()` - -**Transaction Building (ccc.Transaction):** -- Purpose: All managers use plain `ccc.Transaction` (SmartTransaction was deleted in Phase 1) -- Pattern: Managers accept `ccc.TransactionLike` and return `ccc.Transaction` (TransactionLike pattern) -- Key operations: `tx.addCellDeps()`, `tx.addInput()`, `tx.addOutput()`, `tx.headerDeps.push()` -- Fee completion: CCC-native `completeFeeBy()` / `completeFeeChangeToLock()` with DAO-aware 64-output limit check (contributed to CCC core) -- Header caching: Transparently handled by CCC Client Cache (no explicit header map) - -**Value Types (Domain Models):** -- `ValueComponents`: `{ ckbValue: ccc.FixedPoint; udtValue: ccc.FixedPoint }` -- `Info`: Order metadata with ratio bounds, direction, fee tier -- `Ratio`: Exchange rate as scaled numerator/denominator -- `OrderCell`: Extends ValueComponents with order-specific properties -- `OrderGroup`: Wrapper for order cells grouped by master cell -- `SystemState`: Immutable snapshot with fee rate, exchange ratio, order pool, available/maturing CKB - -**Async Generator Pattern (Cell Finding):** -- Signature: `async *find*(client, locks, options?) : AsyncGenerator` -- Examples: `DaoManager.findDeposits()`, `OrderManager.findOrders()` -- Usage: Lazy evaluation with batching via `defaultFindCellsLimit` (400 cells) -- Filtering: Applied after fetch via type checkers and lock script matching -- Collection: Wrapped via `collect()` helper to realize as array - -## Entry Points - -**CLI Entry Points:** - -**Faucet:** -- Location: `apps/faucet/src/main.ts` - `main()` function -- Invocation: Run via `index.ts` or direct execution -- Environment: ADDRESS env variable (recipient CKB address) -- Behavior: Polls every 2 minutes for accumulated CKB, transfers to recipient account - -**Sampler:** -- Location: `apps/sampler/src/index.ts` -- Invocation: Direct execution -- Behavior: Periodic blockchain observation and data sampling - -**Bot:** -- Location: `apps/bot/src/index.ts` - `main()` function -- Invocation: CLI execution -- Environment: CHAIN, RPC_URL, BOT_PRIVATE_KEY, BOT_SLEEP_INTERVAL env variables -- Behavior: Infinite loop matching orders at configurable interval - -**Web Application Entry:** - -**Interface:** -- Location: `apps/interface/src/main.tsx` - `startApp(wallet_chain: string)` function -- Invocation: Called with parameter `"_"` (e.g., `"JoyId_mainnet"`) -- Behavior: Initializes chain config, creates query client, renders React app -- Sets up: CCC client (ClientPublicTestnet or ClientPublicMainnet), JoyId wallet signers, React Query cache - -**SDK Entry:** -- Location: `packages/sdk/src/sdk.ts` - `IckbSdk.from(...args)` static factory -- Invocation: Called by applications during setup -- Behavior: Instantiates all managers from script config, returns fully-composed SDK - -## Error Handling - -**Strategy:** Contract validation with descriptive errors; graceful degradation in apps - -**Patterns:** -- **Validation**: Throw errors for invalid state (e.g., "Not a deposit", "Transaction have different inputs and outputs lengths") -- **Cell not found**: Throw in constructors (`receiptCellFrom()`), return empty generators in finders -- **Configuration**: Throw on missing or invalid environment variables with helpful messages -- **Transaction constraints**: Check limits (e.g., max 64 output cells in DAO transactions) -- **App-level**: Try-catch with JSON error logging including stack traces for monitoring - -**Examples:** -- Bot/Faucet: Log execution JSON with error field containing full stack trace -- Interface: React Query retry logic with exponential backoff -- Managers: Pre-condition checks before transaction mutations (throw early) - -## Cross-Cutting Concerns - -**Logging:** -- Apps: Structured JSON logs with timestamps, success/error status, operation results -- Pattern: Log at operation boundaries (start, end) for monitoring -- Format: `{ startTime, balance?, txHash?, error?, elapsedSeconds }` - -**Validation:** -- Script matching: `script.eq()` calls for type/lock verification -- Cell type checking: Manager predicates (isDeposit, isOrder, isMaster) -- Amount validation: Zero/minimum checks before operations - -**Authentication:** -- Apps: Private key from environment variables (BOT_PRIVATE_KEY) -- Interface: JoyId wallet connector for signing -- Pattern: CCC signers abstract wallet implementation - -**Capacity & Fee Management:** -- CCC-native: `tx.completeFeeBy()` / `tx.completeFeeChangeToLock()` with DAO-aware 64-output limit -- Pattern: Add-then-complete flow (add inputs/outputs, then complete fee via CCC pipeline) -- Note: `CapacityManager` was deleted in Phase 1; capacity discovery uses `client.findCellsOnChain()` directly - -**UDT Handling:** -- `UdtHandler`: Interface encapsulating token script + cell deps -- `UdtManager`: Base implementation with `isUdt()`, `findUdts()`, `completeInputsByUdt()` -- Pattern: Managers hold `UdtHandler` reference; cell deps added via `tx.addCellDeps(udtHandler.cellDeps)` - ---- - -*Architecture analysis: 2026-02-17* diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md deleted file mode 100644 index c616afe..0000000 --- a/.planning/codebase/CONCERNS.md +++ /dev/null @@ -1,253 +0,0 @@ -# Codebase Concerns - -**Analysis Date:** 2026-02-17 - -## Tech Debt - -### Apps Depend on Deprecated Legacy Libraries (Critical) - -- Issue: Three apps (`bot`, `tester`, `interface`) depend on `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2`, which are the legacy deprecated versions that this monorepo's `packages/` are designed to replace. -- Files: - - `apps/bot/package.json` - depends on `@ickb/lumos-utils@^1.4.2`, `@ickb/v1-core@^1.4.2` - - `apps/tester/package.json` - depends on `@ickb/lumos-utils@^1.4.2`, `@ickb/v1-core@^1.4.2` - - `apps/interface/package.json` - depends on `@ickb/lumos-utils@^1.4.2`, `@ickb/v1-core@^1.4.2` - - `apps/bot/src/index.ts` - heavy usage of legacy APIs throughout (~900 lines) - - `apps/tester/src/index.ts` - heavy usage of legacy APIs throughout (~470 lines) - - `apps/interface/src/transaction.ts` - uses `TransactionSkeleton` from Lumos - - `apps/interface/src/queries.ts` - uses `I8Header`, `I8Cell`, `I8Script` from legacy - - `apps/interface/src/utils.ts` - uses `epochSinceAdd`, `parseEpoch` from Lumos, `ickbExchangeRatio` from v1-core -- Impact: The new `packages/` libraries (`@ickb/utils`, `@ickb/core`, `@ickb/dao`, `@ickb/order`, `@ickb/sdk`) cannot be validated in production until these apps are migrated. Any features added to the new libraries need parallel implementation in the old ones for the apps to use them. -- Fix approach: Migrate apps one at a time to use the new `packages/` libraries. The `faucet` app has already been migrated (uses `@ickb/utils` and CCC). The `sampler` app also uses the new packages. Start with `tester` (simplest remaining), then `bot`, then `interface` (most complex, React-based). - -### All `@ckb-lumos/*` Usage is Deprecated (Critical) - -- Issue: Lumos is being replaced by CCC (`ckb-ccc`) ecosystem-wide. The three legacy apps still import extensively from `@ckb-lumos/helpers`, `@ckb-lumos/base`, `@ckb-lumos/hd`, and `@ckb-lumos/common-scripts`. -- Files: - - `apps/bot/src/index.ts` - imports from `@ckb-lumos/helpers`, `@ckb-lumos/common-scripts`, `@ckb-lumos/hd`, `@ckb-lumos/base` - - `apps/tester/src/index.ts` - same Lumos imports - - `apps/interface/src/transaction.ts` - `TransactionSkeletonType` from `@ckb-lumos/helpers` - - `apps/interface/src/queries.ts` - `Cell`, `Header` from `@ckb-lumos/base` - - `apps/interface/src/utils.ts` - `parseEpoch`, `EpochSinceValue` from `@ckb-lumos/base/lib/since` -- Impact: Lumos is deprecated upstream and will eventually stop receiving updates. Security patches and CKB protocol changes will only be reflected in CCC. -- Fix approach: This is resolved by the app migration above. The new `packages/` libraries already use CCC exclusively via `@ckb-ccc/core`. - -### ~~Local Epoch Class Partially Duplicates CCC Upstream~~ (RESOLVED) - -- **Resolved in:** commit ae8b5af (`refactor: replace ickb Epoch with ccc.Epoch`) -- Local `packages/utils/src/epoch.ts` (244 lines) was deleted. All packages now use `ccc.Epoch` directly. - -### Local UDT Handling May Overlap CCC Upstream (Medium) - -- Issue: CCC now has a dedicated `@ckb-ccc/udt` package (at `forks/ccc/packages/udt/`). The local `packages/utils/src/udt.ts` and `packages/core/src/udt.ts` implement custom UDT handling (`UdtHandler` interface, `IckbUdtManager` class). While the local UDT handling is iCKB-specific (custom balance calculation accounting for DAO deposits), the generic UDT operations like `ccc.udtBalanceFrom()` are still being used from CCC upstream in `packages/utils/src/udt.ts` (4 locations). -- Files: - - `packages/utils/src/udt.ts` - `UdtHandler` interface, `UdtManager` class (~370 lines) - - `packages/core/src/udt.ts` - `IckbUdtManager` extending UDT handling for iCKB-specific logic - - `forks/ccc/packages/udt/src/` - CCC upstream UDT package - - Usage of `ccc.udtBalanceFrom()`: `packages/utils/src/udt.ts` lines 169, 197, 323, 368 -- Impact: There may be duplicated utility code for standard UDT operations (finding cells, calculating balances). The iCKB-specific extensions (e.g., `IckbUdtManager` which modifies balance calculations based on DAO deposit/withdrawal state) are domain-specific and unlikely to be in CCC. -- Fix approach: Audit the CCC `@ckb-ccc/udt` package to identify which local utilities can be replaced. Keep iCKB-specific extensions but delegate standard UDT operations (cell finding, basic balance) to CCC where possible. - -### Fragile CCC Local Override Mechanism (Medium) - -- Issue: The `.pnpmfile.cjs` hook and `forks/forker/record.sh` script create a fragile mechanism for overriding published CCC packages with local builds. The `.pnpmfile.cjs` `readPackage` hook intercepts pnpm's dependency resolution to redirect `@ckb-ccc/*` packages to local paths under `forks/ccc/packages/*/`. -- Files: - - `.pnpmfile.cjs` - pnpm hook that overrides `@ckb-ccc/*` package resolutions - - `forks/forker/record.sh` - generic fork record script (clones repo, merges refs, builds locally) - - `forks/config.json` - CCC fork configuration (upstream URL, refs, workspace config) - - `pnpm-workspace.yaml` - includes `forks/ccc/packages/*` in workspace (auto-generated section) - - `forks/ccc/` - local CCC checkout (when present) -- Impact: Multiple fragility points: - 1. The local CCC repo at `forks/ccc/` must be manually cloned and kept in sync with a specific branch/commit. - 2. The `readPackage` hook modifies `dependencies` objects at install time, which can silently break if CCC reorganizes its packages. - 3. CI/CD (`forks/forker/replay.sh`) must run this setup before `pnpm install`, creating an ordering dependency. - 4. The override mechanism is invisible to developers who don't read `.pnpmfile.cjs`, leading to confusion when packages resolve differently than expected from `package.json`. -- Fix approach: Now that UDT and Epoch PRs have been merged into CCC upstream, evaluate whether the local overrides are still needed. If CCC publishes releases containing the merged features, switch to published versions and remove the override mechanism. - -## Known Bugs - -### ~~Faucet `main()` Runs Diagnostic Code Instead of Faucet Logic~~ (RESOLVED) - -- **Resolved:** Faucet was restructured. `apps/faucet/src/index.ts` now imports and calls `main()` from `apps/faucet/src/main.ts` which contains the actual faucet transfer logic (88 lines). - -### ~~Self-Comparison Bug in Pool Snapshot Maturity Calculation~~ (INVALID) - -- **Invalid:** The original analysis incorrectly stated the condition was `tipEpoch.compare(tipEpoch) < 0` (self-comparison). The actual code at `packages/sdk/src/sdk.ts` line 443 is `start.compare(tipEpoch) < 0`, which correctly checks whether the bin start epoch precedes the current tip epoch. No bug exists. - -## Security Considerations - -### Private Keys in Environment Variables - -- Risk: Both `apps/bot/src/index.ts` and `apps/tester/src/index.ts` read private keys directly from environment variables (`BOT_PRIVATE_KEY`, `TESTER_PRIVATE_KEY`) and use them in-process for transaction signing via `@ckb-lumos/hd` `key.signRecoverable()`. -- Files: - - `apps/bot/src/index.ts`, lines 67-68, 859-884 (key usage in `secp256k1Blake160` and `signer`) - - `apps/tester/src/index.ts`, lines 51, 59-60, 420-467 (same pattern) -- Current mitigation: No `.env` files found committed to the repo. Keys are validated as non-empty before use. -- Recommendations: For production bot operations, consider using a dedicated key management solution or hardware signing. Document required environment variables without example values. - -### Faucet Logs Ephemeral Private Key to Console - -- Risk: `apps/faucet/src/main.ts` generates a temporary private key using `crypto.getRandomValues()` at line 26 and logs the key to console at line 27 (`console.log(key)`). -- Files: `apps/faucet/src/main.ts`, lines 26-27 -- Current mitigation: The key is ephemeral and only used for testnet faucet transfers. -- Recommendations: Avoid logging private keys even in development/testnet contexts. Keep the key in memory only. - -### Hardcoded Script Constants - -- Risk: On-chain script code hashes, dep group outpoints, and known bot addresses are hardcoded in `packages/sdk/src/constants.ts`. If any on-chain script is upgraded or redeployed, these constants must be manually updated. -- Files: `packages/sdk/src/constants.ts`, lines 112-205 (DAO, UDT, ICKB_LOGIC, OWNED_OWNER, ORDER script hashes, dep groups, bot addresses) -- Current mitigation: Separate mainnet and testnet constants. The `getConfig()` function accepts devnet configuration as an alternative to hardcoded values. -- Recommendations: Consider loading constants from an on-chain registry or configuration file for easier updates. - -## Performance Bottlenecks - -### Sequential Header Fetching in DAO Cell Construction - -- Problem: `daoCellFrom()` in `packages/dao/src/cells.ts` fetches headers sequentially using `await getHeader()`. For withdrawal requests, it makes 2 sequential RPC calls (deposit header by block number, then withdrawal request header by txHash). When processing multiple DAO cells in a loop (e.g., in `DaoManager.findDeposits()` or `OwnedOwnerManager.findWithdrawalGroups()`), these are sequential per cell. -- Files: - - `packages/dao/src/cells.ts`, lines 87-116 (sequential header fetching) - - `packages/dao/src/dao.ts`, lines 326-334 (called in async generator loop) - - `packages/core/src/owned_owner.ts`, lines 229-234 (same pattern) -- Cause: Each `daoCellFrom()` call makes 1-2 RPC calls that cannot be parallelized within a single cell construction. -- Improvement path: CCC's Client Cache transparently caches fetched headers (SmartTransaction's header cache was deleted in Phase 1). For batch operations, consider prefetching all needed headers in parallel before constructing DAO cells. - -### Duplicated RPC Batching Code in Legacy Apps - -- Problem: `apps/bot/src/index.ts`, `apps/tester/src/index.ts`, and `apps/interface/src/queries.ts` each contain nearly identical implementations of `getTxsOutputs()`, `getHeadersByNumber()`, `getMixedCells()`, and `secp256k1Blake160()`, each with their own manual RPC batch management and in-memory caching. -- Files: - - `apps/bot/src/index.ts`, lines 722-827 (getTxsOutputs, getHeadersByNumber, getMixedCells) - - `apps/tester/src/index.ts`, lines 315-467 (same functions, plus secp256k1Blake160) - - `apps/interface/src/queries.ts`, lines 270-376 (same functions) -- Cause: These are pre-migration legacy code patterns. The new `packages/` libraries use CCC's built-in client caching. -- Improvement path: Resolved by migrating apps to new packages, which handle caching through `ccc.Client` methods like `findCells()` and `findCellsOnChain()`. - -### Unbounded In-Memory Caches in Bot - -- Problem: Global mutable maps `_knownHeaders` and `_knownTxsOutputs` in `apps/bot/src/index.ts` accumulate indefinitely without eviction. -- Files: `apps/bot/src/index.ts`, lines 793 (`_knownTxsOutputs`), 827 (`_knownHeaders`) -- Cause: `Object.freeze()` on the map prevents modification but new maps are created and assigned on each fetch cycle, with old data carried over. -- Improvement path: Implement LRU cache with size limits or TTL-based expiration. Alternatively, this is resolved by migrating the bot to new packages which use CCC's client-side caching. - -## Fragile Areas - -### SmartTransaction Class Extending ccc.Transaction (RESOLVED) - -- Status: **Resolved in Phase 1** — SmartTransaction class and CapacityManager were fully deleted from `@ickb/utils`. All manager methods now accept `ccc.TransactionLike` and return `ccc.Transaction` directly. Header caching is handled by CCC Client Cache. The 64-output DAO limit check was contributed to CCC core. - -### Bot Order Matching Algorithm - -- Files: `apps/bot/src/index.ts`, lines 272-399 (`bestPartialFilling`, `partialsFrom`) -- Why fragile: Complex recursive algorithm with memoization (`alreadyVisited` map) that depends on consistent `evaluate` function behavior. Random shuffling at lines 351-356 (`Math.random() > 0.9` triggers shuffle) makes output non-deterministic. The matching explores a 2D grid of CKB-to-UDT and UDT-to-CKB partial fills. -- Safe modification: Add comprehensive logging of decision path. Test with deterministic random seed. Add invariant checks that total gain is non-negative. -- Test coverage: No unit tests for matching algorithm. - -### Hardcoded Script Constants in SDK - -- Files: `packages/sdk/src/constants.ts`, lines 112-205 -- Why fragile: Script code hashes, dep group outpoints, and known bot addresses are hardcoded. If any on-chain script is upgraded or redeployed, these constants silently produce wrong results (transactions would fail on-chain but the SDK would not throw beforehand). -- Safe modification: Only change constants after verifying the new values on-chain. Test against both testnet and mainnet. -- Test coverage: No tests verify these constants match on-chain state. - -## Scaling Limits - -### 64 Output Cell Limit for NervosDAO Transactions - -- Current capacity: Maximum 64 output cells per transaction containing NervosDAO operations. -- Limit: Enforced by the NervosDAO script itself. Consolidated into CCC core in Phase 1. -- Files: - - `forks/ccc/packages/core/src/ckb/transaction.ts` — `assertDaoOutputLimit` utility + `completeFee` safety net (contributed to CCC core in Phase 1) - - `packages/dao/src/dao.ts` — calls `assertDaoOutputLimit` - - `packages/core/src/owned_owner.ts` — calls `assertDaoOutputLimit` - - `apps/bot/src/index.ts`, line 414 (limits to 58 outputs to reserve 6 for change) -- Scaling path: Protocol-level constraint. The bot works around it by limiting deposit/withdrawal operations per transaction. Future NervosDAO script updates may relax this. - -## Dependencies at Risk - -### `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2` - -- Risk: Legacy deprecated packages that this monorepo is replacing. They depend on the deprecated `@ckb-lumos/*` ecosystem. No further updates are expected. -- Impact: Three apps (`bot`, `tester`, `interface`) depend on these. Cannot receive bug fixes or new features. -- Migration plan: Migrate apps to use the new `packages/` libraries (`@ickb/utils`, `@ickb/core`, `@ickb/dao`, `@ickb/order`, `@ickb/sdk`). - -### `@ckb-lumos/*` Packages (All Deprecated) - -- Risk: The entire Lumos framework is deprecated in favor of CCC. These packages may stop receiving security updates. -- Impact: Used by `@ickb/lumos-utils` and directly in legacy apps. -- Migration plan: Already addressed by new packages using CCC. Remove Lumos dependencies when apps are migrated. - -### React Compiler Plugins Unpinned - -- Risk: `babel-plugin-react-compiler` and `eslint-plugin-react-compiler` in `apps/interface/package.json` are using `latest` tag without version pinning (lines 29, 31). -- Impact: Unpredictable behavior changes when new versions are released; no reproducible builds. -- Migration plan: Pin to specific versions once the React compiler stabilizes. - -## Missing Critical Features - -### No Automated Tests - -- Problem: Zero test files exist in the project source code (all `*.test.*` and `*.spec.*` files are in `node_modules/`). The CI pipeline (`.github/workflows/check.yaml`) runs `pnpm check` which includes `pnpm test:ci`, but with no test files, `vitest run` passes vacuously. -- Blocks: Confident refactoring, library migration, and CCC upstream updates. Any code change is a regression risk. -- Files: `.github/workflows/check.yaml` - -### No Published Package Versions - -- Problem: All packages in `packages/` have version `1001.0.0` (Epoch Semantic Versioning placeholder) in their `package.json` files. None have been published to npm yet. -- Blocks: External consumers cannot depend on the new libraries. External projects still must use the deprecated `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2`. -- Files: - - `packages/utils/package.json` - version `1001.0.0` - - `packages/core/package.json` - version `1001.0.0` - - `packages/dao/package.json` - version `1001.0.0` - - `packages/order/package.json` - version `1001.0.0` - - `packages/sdk/package.json` - version `1001.0.0` - -## Test Coverage Gaps - -### Entire Codebase is Untested - -- What's not tested: Every package and every app. Zero test files in the project. -- Files: All files under `packages/` and `apps/` -- Risk: The financial logic in `packages/sdk/src/sdk.ts` (order matching, maturity estimation, CKB/UDT conversion), `packages/order/src/order.ts` (order matching algorithm with complex bigint arithmetic), and `packages/dao/src/cells.ts` (DAO interest calculation, maturity computation) handle real cryptocurrency operations. Bugs in these areas could lead to financial loss. -- Priority: High. At minimum, the following should have unit tests: - 1. `packages/utils/src/utils.ts` - `binarySearch`, `asyncBinarySearch`, `gcd`, `min`, `max`, `sum`, `hexFrom`, `isHex`, `shuffle` - 2. `packages/utils/src/codec.ts` - `CheckedInt32LE` encode/decode - 3. `packages/order/src/entities.ts` - `Ratio.applyFee()`, `Ratio.convert()`, `Info.validate()` - 4. `packages/order/src/order.ts` - `OrderMatcher.match()`, `OrderMatcher.nonDecreasing()`, `OrderManager.bestMatch()` - 5. `packages/sdk/src/codec.ts` - `PoolSnapshot` encode/decode roundtrip - 6. `packages/dao/src/cells.ts` - `daoCellFrom()` maturity/interest calculations - 7. `packages/core/src/logic.ts` - iCKB exchange ratio and conversion logic - -### TS Exchange Rate Must Match Rust Contract Logic - -- What's not tested: The TypeScript exchange rate calculation (`packages/core/src/udt.ts`) must produce identical results to the Rust contract's `deposit_to_ickb()` function (`forks/contracts/scripts/contracts/ickb_logic/src/entry.rs`). Any discrepancy would cause transactions to be rejected on-chain. -- Key formula: `iCKB = capacity * AR_0 / AR_m` with soft cap penalty `amount - (amount - 100000) / 10` when `amount > ICKB_SOFT_CAP_PER_DEPOSIT` -- Contract constants that TS must match: - - `CKB_MINIMUM_UNOCCUPIED_CAPACITY_PER_DEPOSIT = 1,000 * 100_000_000` (1,000 CKB) - - `CKB_MAXIMUM_UNOCCUPIED_CAPACITY_PER_DEPOSIT = 1,000,000 * 100_000_000` (1,000,000 CKB) - - `ICKB_SOFT_CAP_PER_DEPOSIT = 100,000 * 100_000_000` (100,000 iCKB) - - `GENESIS_ACCUMULATED_RATE = 10_000_000_000_000_000` (10^16) -- Reference: `forks/contracts/scripts/contracts/ickb_logic/src/entry.rs` function `deposit_to_ickb()` -- Fix approach: Add cross-validation tests with known inputs/outputs derived from the Rust contract logic - -### TS Molecule Codecs Must Match Contract Schemas - -- What's not tested: The TypeScript Molecule codec definitions (`@ccc.codec` decorators in `packages/order/src/entities.ts`, `packages/core/src/entities.ts`) must produce byte-identical encodings to the Molecule schema at `forks/contracts/schemas/encoding.mol`. Field order, sizes, and endianness must match exactly. -- Key schemas: - - `ReceiptData { deposit_quantity: Uint32, deposit_amount: Uint64 }` = 12 bytes - - `OwnedOwnerData { owned_distance: Int32 }` = 4 bytes - - `Ratio { ckb_multiplier: Uint64, udt_multiplier: Uint64 }` = 16 bytes - - `OrderInfo { ckb_to_udt: Ratio, udt_to_ckb: Ratio, ckb_min_match_log: Uint8 }` = 33 bytes - - Order cell data: `[UDT amount (16)] [Action (4)] [TX hash/padding (32)] [Index/distance (4)] [OrderInfo (33)] = 89 bytes` -- Fix approach: Add codec roundtrip tests using known byte vectors from the Rust contract tests or manually constructed from the Molecule schema - -## Dead Code - -### `fromLumosSkeleton` in SmartTransaction (RESOLVED) - -- Status: **Resolved in Phase 1** — SmartTransaction class was fully deleted, including `fromLumosSkeleton()`. - -### SmartTransaction Name is Misleading (RESOLVED) - -- Status: **Resolved in Phase 1** — SmartTransaction class was fully deleted from `@ickb/utils`. All manager methods now accept `ccc.TransactionLike` directly. - ---- - -*Concerns audit: 2026-02-17* diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md deleted file mode 100644 index 36d2ceb..0000000 --- a/.planning/codebase/CONVENTIONS.md +++ /dev/null @@ -1,373 +0,0 @@ -# Coding Conventions - -**Analysis Date:** 2026-02-17 - -## Important Context - -**Tooling:** -- `gh` CLI is NOT available and must NOT be installed. PR and review workflows are handled inline by the AI Coworker (see AGENTS.md). - -**Legacy vs. New code:** -- `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2` are **LEGACY and DEPRECATED** npm packages. The apps (`apps/bot`, `apps/tester`, `apps/interface`) still depend on them. -- The `packages/` directory contains the **NEW replacement libraries** built on CCC (ckb-ccc), which will eventually replace the legacy packages in the apps. -- All `@ckb-lumos/*` packages are **DEPRECATED** -- Lumos is being replaced by CCC. -- CCC PRs for UDT and Epochs have been **MERGED** upstream -- those features now exist in CCC itself. -- `SmartTransaction` was **DELETED** in Phase 1 in favor of CCC's client cache for header caching. Headers are now fetched inline via CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`). All manager method signatures now accept `ccc.TransactionLike` and return `ccc.Transaction` directly. -- CCC is sometimes overridden locally via `bash forks/forker/record.sh` and `.pnpmfile.cjs` for testing unpublished changes. - -**When writing new code:** Use CCC (`@ckb-ccc/core`) types and patterns exclusively in `packages/`. Never introduce new Lumos dependencies. - -## Naming Patterns - -**Files:** -- Use `snake_case` for multi-word source files: `owned_owner.ts` -- Use single lowercase words when possible: `cells.ts`, `entities.ts`, `logic.ts`, `codec.ts`, `utils.ts`, `heap.ts`, `udt.ts` -- Every package has an `index.ts` barrel file that re-exports everything -- Config files at root use dot-prefix convention: `prettier.config.cjs`, `eslint.config.mjs`, `vitest.config.mts` - -**Functions:** -- Use `camelCase` for all functions: `binarySearch`, `asyncBinarySearch`, `hexFrom`, `isHex`, `collect` -- Prefix boolean-returning functions with `is`: `isHex()`, `isDeposit()`, `isUdt()`, `isReceipt()`, `isCkb2Udt()`, `isMatchable()`, `isFulfilled()` -- Use `tryFrom` for fallible constructors that return `undefined` on failure: `OrderCell.tryFrom()`, `OrderGroup.tryFrom()` -- Use `mustFrom` for throwing constructors: `OrderCell.mustFrom()` -- Use `from` for static factory methods: `Ratio.from()`, `Info.from()`, `Epoch.from()`, `MasterCell.from()` -- Use `validate()` for throwing validation and `isValid()` for boolean validation -- always as a pair - -**Variables:** -- Use `camelCase` for variables and parameters: `ckbScale`, `udtScale`, `tipHeader`, `feeRate` -- Use `UPPER_SNAKE_CASE` for constants: `ICKB_SOFT_CAP_PER_DEPOSIT`, `ICKB_DEPOSIT_CAP` -- Prefix private module-level mutable state with underscore: `_knownHeaders`, `_knownTxsOutputs` - -**Types/Interfaces:** -- Use `PascalCase` for types, interfaces, and classes: `Ratio`, `Info`, `OrderData`, `OrderCell`, `Epoch` -- Suffix data-transfer / input interfaces with `Like`: `InfoLike`, `RelativeLike`, `OrderDataLike`, `MasterLike`, `EpochLike` -- The `Like` type is the "encodable" or input representation; the plain name is the decoded/validated form -- Use `ValueComponents` interface for anything with `ckbValue` and `udtValue` properties - -**Classes:** -- Use `PascalCase`: `MinHeap`, `BufferedGenerator`, `UdtManager`, `DaoManager`, `LogicManager`, `OrderManager`, `OwnedOwnerManager`, `IckbSdk` -- Manager classes implement `ScriptDeps` interface and contain `script` and `cellDeps` properties -- Generic type parameters use single capital letters: ``, `` - -## Code Style - -**Formatting:** -- Prettier with `prettier-plugin-organize-imports` -- Double quotes (not single quotes): `singleQuote: false` -- Trailing commas everywhere: `trailingComma: "all"` -- Config: `prettier.config.cjs` -- Interface app additionally uses `prettier-plugin-tailwindcss` via `apps/interface/.prettierrc` - -**Linting:** -- ESLint with `typescript-eslint` strict type-checked config -- Root config: `eslint.config.mjs` -- Interface has its own ESLint config: `apps/interface/eslint.config.mjs` (adds React plugins) -- Key enforced rule: `@typescript-eslint/explicit-function-return-type: "error"` -- every function must have an explicit return type annotation -- Strict type checking enabled (`tseslint.configs.strictTypeChecked`) - -**TypeScript Compiler:** -- Root `tsconfig.json` targets `ES2020` with `NodeNext` module resolution -- `strict: true` with additional strict checks: - - `noUnusedLocals: true` - - `noUnusedParameters: true` - - `noFallthroughCasesInSwitch: true` - - `noUncheckedIndexedAccess: true` - - `noImplicitOverride: true` - - `noImplicitAny: true` - - `noEmitOnError: true` -- `verbatimModuleSyntax: true` -- use `import type` for type-only imports -- `declaration: true`, `declarationMap: true`, `sourceMap: true` -- `removeComments: true`, `stripInternal: true` -- comments stripped from output, `@internal` members excluded from .d.ts -- Required Node.js version: `>=24` - -## Import Organization - -**Order (enforced by `prettier-plugin-organize-imports`):** -1. External dependencies (`@ckb-ccc/core`, `@ckb-lumos/*`, `crypto`, `process`) -2. Internal workspace packages (`@ickb/utils`, `@ickb/core`, `@ickb/dao`, `@ickb/order`) -3. Relative imports (`./entities.js`, `./cells.js`, `./utils.js`) - -**Style:** -- Always use `.js` extension in relative imports (required by `NodeNext` resolution): `import { gcd } from "./utils.js";` -- Use `import type` for type-only imports: `import type { UdtHandler } from "./udt.js";` -- Mixed imports combine values and types: `import { unique, type ValueComponents } from "./utils.js";` -- Destructure imports at the top: `import { ccc, mol } from "@ckb-ccc/core";` -- Named exports only -- no default exports anywhere in the codebase - -**Path Aliases:** -- None. All imports use bare specifiers for packages and relative paths within packages. - -## Error Handling - -**Patterns:** - -1. **Throw `Error` directly** -- never custom error classes except `ErrorTransactionInsufficientCoin` in `packages/utils/src/udt.ts`: -```typescript -throw Error("Ratio invalid: not empty, not populated"); -throw Error("iCKB deposit minimum is 1082 CKB"); -throw Error("Header not found"); -``` - -2. **validate() / isValid() pair** -- consistent throughout the codebase. Use this pair on all domain entities: -```typescript -validate(): void { - if (/* invalid condition */) { - throw Error("Description of what is wrong"); - } -} - -isValid(): boolean { - try { - this.validate(); - return true; - } catch { - return false; - } -} -``` -This pattern appears in: `Ratio` (`packages/order/src/entities.ts`), `Info` (same file), `Relative` (same file), `OrderData` (same file), `OrderCell` (`packages/order/src/cells.ts`), `OrderGroup` (same file), `MasterCell` (same file) - -3. **tryFrom / mustFrom factory pair** for parsing from raw blockchain data: -```typescript -// packages/order/src/cells.ts -static tryFrom(cell: ccc.Cell): OrderCell | undefined { - try { - return OrderCell.mustFrom(cell); - } catch { - return undefined; - } -} - -static mustFrom(cell: ccc.Cell): OrderCell { - const data = OrderData.decode(cell.outputData); - data.validate(); - // ... construct and return -} -``` - -4. **Env var validation at app entry** -- check and throw immediately: -```typescript -// apps/bot/src/index.ts, apps/tester/src/index.ts -if (!CHAIN) { - throw Error("Invalid env CHAIN: Empty"); -} -if (!isChain(CHAIN)) { - throw Error("Invalid env CHAIN: " + CHAIN); -} -``` - -5. **Async error handling in app loops** -- catch, log structured JSON, continue: -```typescript -// apps/bot/src/index.ts, apps/tester/src/index.ts, apps/faucet/src/main.ts -try { - // ... main logic -} catch (e) { - if (e instanceof Object && "stack" in e) { - /* eslint-disable-next-line @typescript-eslint/no-misused-spread */ - executionLog.error = { ...e, stack: e.stack ?? "" }; - } else { - executionLog.error = e ?? "Empty Error"; - } -} -console.log(JSON.stringify(executionLog, replacer, " ")); -``` - -## Logging - -**Framework:** `console` only -- no logging framework. - -**Patterns:** -- Apps log structured JSON via `console.log(JSON.stringify(executionLog, replacer, " "))` where `replacer` converts `bigint` to `number` -- The sampler app (`apps/sampler/src/index.ts`) logs CSV output directly -- Library packages (`packages/*`) do not log -- they only throw errors - -**BigInt serialization helper** used in apps: -```typescript -function replacer(_: unknown, value: unknown): unknown { - return typeof value === "bigint" ? Number(value) : value; -} -``` - -## Comments - -**When to Comment:** -- Use JSDoc (`/** ... */`) for all public functions, methods, classes, and interfaces in `packages/` -- Include `@param`, `@returns`, `@throws`, `@example`, `@remarks` tags as appropriate -- Use `@internal` tag for functions that should be excluded from generated declarations -- Use `@credits` for code ported from other languages (Go standard library translations in `packages/utils/src/utils.ts`, `packages/utils/src/heap.ts`) -- Use `@link` for referencing external resources -- Inline comments (`//`) explain non-obvious logic like bit operations or mathematical formulas -- The sampler app uses `@packageDocumentation` at the module level - -**TypeDoc / Documentation:** -- TypeDoc generates API documentation from JSDoc, configured via `typedoc.base.json` -- Sort order: `source-order, alphabetical, kind` -- Source links point to GitHub master branch -- Each package has its own `typedoc.json` extending the base - -**eslint-disable comments** are used sparingly for known-safe patterns: -```typescript -/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ -/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */ -/* eslint-disable-next-line @typescript-eslint/no-misused-spread */ -/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */ -``` - -## Function Design - -**Size:** Functions are generally compact (under 50 lines). Longer functions exist in the apps for transaction orchestration but are organized into clear named sub-functions. - -**Parameters:** -- Use object destructuring for multi-field inputs: `{ ckbScale, udtScale }`, `{ cell, data, ckbUnoccupied, ... }` -- Use `options?` objects for optional parameters with defaults: -```typescript -// packages/dao/src/dao.ts -async *findDeposits( - client: ccc.Client, - locks: ccc.Script[], - options?: { - tip?: ccc.ClientBlockHeader; - onChain?: boolean; - minLockUp?: Epoch; - maxLockUp?: Epoch; - limit?: number; - }, -): AsyncGenerator { ... } -``` -- Use variadic args: `sum(res: bigint, ...rest: bigint[])`, `isOwner(...locks: ccc.Script[])` - -**Return Values:** -- Use tuples for multi-value returns: `Promise<[number, boolean]>`, `[ccc.FixedPoint, ccc.FixedPoint]` -- Use `| undefined` instead of `null` for missing values: `OrderCell | undefined` -- Use explicit `void` return for side-effect-only functions -- All return types must be explicit (enforced by ESLint) - -## Module Design - -**Exports:** -- Every package uses barrel exports via `index.ts`: `export * from "./cells.js";` -- All exports are named, never default -- Type-only exports use `export type` in conjunction with `verbatimModuleSyntax` - -**Barrel Files:** -- Located at `packages/*/src/index.ts` -- Re-export everything from each source module -- No logic in barrel files -- Example (`packages/utils/src/index.ts`): -```typescript -export * from "./codec.js"; -export * from "./heap.js"; -export * from "./udt.js"; -export * from "./utils.js"; -``` - -**Package structure (identical for all `packages/*`):** -- `src/index.ts` - barrel exports -- `src/*.ts` - source files -- `package.json` - with `"type": "module"`, `"sideEffects": false`, `"main": "dist/index.js"`, `"types": "dist/index.d.ts"` -- `tsconfig.json` - extends root `../../tsconfig.json`, sets `rootDir: "src"`, `outDir: "dist"` -- `vitest.config.mts` - test configuration (includes `src/**/*.test.ts`) - -## Molecule / Codec Patterns - -**TS codecs must match the Molecule schema** at `forks/contracts/schemas/encoding.mol`. The on-chain contracts use Molecule for serialization; the TS packages must produce byte-identical encodings. - -**Entity classes** use CCC's `ccc.Entity.Base` with decorator-based codec definition: -```typescript -// packages/order/src/entities.ts -@ccc.codec( - mol.struct({ - ckbScale: mol.Uint64, - udtScale: mol.Uint64, - }), -) -export class Ratio extends ccc.Entity.Base() { - constructor( - public ckbScale: ccc.Num, - public udtScale: ccc.Num, - ) { - super(); - } - - static override from(ratio: ExchangeRatio): Ratio { - if (ratio instanceof Ratio) { - return ratio; - } - const { ckbScale, udtScale } = ratio; - return new Ratio(ckbScale, udtScale); - } -} -``` - -Key conventions for entity classes: -- Two generic parameters: `` -- Constructor takes decoded/validated fields with `public` modifier -- Static `from()` method overrides base, short-circuits on `instanceof` check -- `validate()` and `isValid()` pair for validation -- Static helper constructors: `Ratio.empty()`, `Info.create()` - -## BigInt Usage - -- Use `bigint` for all blockchain numeric values (capacity, amounts, block numbers, epochs) -- Use `0n` for zero, `1n` for one -- Use `ccc.Num` (alias for `bigint`) and `ccc.FixedPoint` (alias for `bigint`) for type clarity -- Bit operations on bigints: `1n << BigInt(this.ckbMinMatchLog)`, `n >> 1` -- Use `Number()` only when interfacing with JS APIs that require it -- Formatting for display: `ccc.fixedPointToString()` or custom `fmtCkb()` in apps - -## Immutability Patterns - -- Use `Object.freeze()` extensively for shared data: -```typescript -// apps/bot/src/index.ts -const frozenResult = Object.freeze(result); -Object.freeze(tx.outputs.map(...)); -let origins: readonly I8Cell[] = Object.freeze([]); -``` -- Use `readonly` on class fields and interface members where appropriate -- Use `Readonly` wrapper type for maps and objects: `Readonly>` - -## Async Generator Pattern - -Finder methods throughout the library use `async *` generators for lazy iteration: -```typescript -// packages/utils/src/udt.ts -async *findUdts( - client: ccc.Client, - locks: ccc.Script[], - options?: { onChain?: boolean; limit?: number }, -): AsyncGenerator { - const limit = options?.limit ?? defaultFindCellsLimit; - for (const lock of unique(locks)) { - // ... RPC query setup ... - for await (const cell of client.findCells(...findCellsArgs)) { - if (!this.isUdt(cell) || !cell.cellOutput.lock.eq(lock)) { - continue; - } - yield { cell, ckbValue: cell.cellOutput.capacity, udtValue: ccc.udtBalanceFrom(cell.outputData), [isUdtSymbol]: true }; - } - } -} -``` - -To collect results into an array, use the `collect()` helper from `packages/utils/src/utils.ts`: -```typescript -const udts = await collect(udtManager.findUdts(client, locks)); -``` - -## App Entry Points - -- Apps use top-level `await` at the end of the module: -```typescript -// apps/sampler/src/index.ts -await main(); -process.exit(0); -``` -- Legacy apps (`apps/bot`, `apps/tester`) use `for (;;)` infinite loops with sleep -- New apps (`apps/faucet`, `apps/sampler`) also use `for (;;)` or run-once patterns -- All apps are ESM (`"type": "module"` in package.json) -- Build command for all: `tsc` (compile only, no bundler except for `apps/interface` which uses Vite) - ---- - -*Convention analysis: 2026-02-17* diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md deleted file mode 100644 index 1c068b6..0000000 --- a/.planning/codebase/INTEGRATIONS.md +++ /dev/null @@ -1,283 +0,0 @@ -# External Integrations - -**Analysis Date:** 2026-02-17 - -## APIs & External Services - -### CKB Blockchain RPC (Primary Integration) - -All interaction with the Nervos CKB Layer 1 blockchain happens via JSON-RPC 2.0. This is the single external service the project depends on. - -**New CCC-based clients:** -- `ccc.ClientPublicTestnet()` - Public CKB testnet RPC endpoint - - Used in: `apps/faucet/src/main.ts`, `apps/interface/src/main.tsx` -- `ccc.ClientPublicMainnet()` - Public CKB mainnet RPC endpoint - - Used in: `apps/sampler/src/index.ts`, `apps/interface/src/main.tsx` -- Custom RPC URL supported via env var in bot - -**Legacy Lumos-based clients (DEPRECATED):** -- `chainConfigFrom(CHAIN, RPC_URL, true, getIckbScriptConfigs)` - Configures Lumos RPC client - - Used in: `apps/bot/src/index.ts`, `apps/interface/src/main.tsx` -- Public endpoints used: `https://testnet.ckb.dev/`, `https://mainnet.ckb.dev/` -- `rpc.getCellsByLock()`, `rpc.getTransaction()`, `rpc.getHeaderByNumber()`, `rpc.sendTransaction()` - Direct Lumos RPC calls in `apps/bot/src/index.ts` -- `rpc.createBatchRequest()` - Batch RPC requests for efficiency in `apps/bot/src/index.ts` - -**CCC Client RPC methods used by new packages:** -- `client.findCells()` / `client.findCellsOnChain()` - Cell queries with script/type filters - - Used in: `packages/utils/src/capacity.ts`, `packages/utils/src/udt.ts`, `packages/dao/src/dao.ts`, `packages/order/src/order.ts`, `packages/core/src/logic.ts`, `packages/core/src/owned_owner.ts` -- `client.getTipHeader()` - Get latest block header - - Used in: `packages/sdk/src/sdk.ts`, `packages/dao/src/dao.ts`, `packages/core/src/owned_owner.ts` -- `client.getHeaderByNumber()` / `client.getHeaderByHash()` - Get block headers - - Used in: `packages/utils/src/utils.ts`, `apps/sampler/src/index.ts` -- `client.getHeaderByNumberNoCache()` - Uncached header fetch - - Used in: `apps/faucet/src/main.ts` -- `client.getTransactionWithHeader()` - Get transaction with its block header - - Used in: `packages/utils/src/utils.ts` -- `client.getCell()` - Get individual cell by outpoint - - Used in: `packages/order/src/order.ts` -- `client.getKnownScript()` - Get well-known scripts (NervosDAO) - - Used in: `packages/utils/src/transaction.ts` -- `client.getFeeRate()` - Get current fee rate - - Used in: `packages/sdk/src/sdk.ts` -- `signer.sendTransaction()` - Submit signed transactions - - Used in: `apps/faucet/src/main.ts`, `apps/interface/src/Connector.tsx` - -### CKB Public RPC Endpoints - -**Testnet:** -- URL: `https://testnet.ckb.dev/` -- Used by: `apps/interface/src/main.tsx`, `apps/bot` (configurable) - -**Mainnet:** -- URL: `https://mainnet.ckb.dev/` -- Used by: `apps/interface/src/main.tsx`, `apps/bot` (configurable) - -**Custom:** -- Configurable via `RPC_URL` env var in `apps/bot` -- CCC public clients wrap official public endpoints by default - -### Nervos Explorer (Links Only) - -- Used for user-facing links in `apps/interface` -- Pattern: `https://[testnet.]explorer.nervos.org/address/{address}` -- No API integration, just URL construction - -## Data Storage - -**Databases:** -- None. All state is read directly from the CKB L1 blockchain via RPC queries. There is no database. - -**File Storage:** -- Local filesystem only. No cloud storage. -- `apps/bot`: Logs to `log_${CHAIN}_$(date +%F_%H-%M-%S).json` via stdout pipe to `tee` -- `apps/sampler`: Outputs CSV to `rate.csv` via stdout pipe to `tee` - -**Caching:** -- CCC Client Cache (in-memory): CCC caches block headers and cell data internally. This is the primary cache mechanism for the new packages. -- SmartTransaction headers cache: `packages/utils/src/transaction.ts` maintains a `Map` for header lookups during transaction building. NOTE: SmartTransaction's header caching was the abandoned concept; CCC's built-in Client Cache is the replacement. -- TanStack React Query (in-memory, client-side): `apps/interface` uses React Query for frontend state caching -- Lumos in-memory caching: `apps/bot/src/index.ts` maintains `_knownHeaders` and `_knownTxsOutputs` maps for cross-iteration caching - -## Authentication & Identity - -**Wallet Signing (CCC-based):** -- `ccc.SignerCkbPrivateKey` - Private key signer for programmatic signing - - Used in: `apps/faucet/src/main.ts` (generates random ephemeral keys) -- JoyId Signer - Browser wallet integration - - Used in: `apps/interface/src/main.tsx` via `JoyId.getJoyIdSigners()` - - CCC's `@ckb-ccc/ccc` package provides wallet connector framework -- `signer.connect()`, `signer.isConnected()`, `signer.getRecommendedAddress()`, `signer.getAddressObjs()` - Wallet connection flow - - Used in: `apps/interface/src/Connector.tsx` -- `signer.prepareTransaction()`, `signer.sendTransaction()` - Transaction signing and submission - - Used in: `apps/interface/src/Connector.tsx` - -**Legacy Signing (Lumos-based, DEPRECATED):** -- secp256k1_blake160 signing via `@ckb-lumos/hd` - - Used in: `apps/bot/src/index.ts` - `key.privateToPublic()`, `key.signRecoverable()` - - `prepareSigningEntries()` + `sealTransaction()` from `@ckb-lumos/helpers` - -**Key Management:** -- `BOT_PRIVATE_KEY` env var - Bot's signing private key (`apps/bot`) -- Ephemeral keys - `apps/faucet` generates random 32-byte keys via `crypto.getRandomValues()` -- Browser wallets - `apps/interface` delegates to connected wallet (JoyId) -- No centralized key storage - -## Smart Contracts (On-Chain Scripts) - -The project interacts with several on-chain CKB scripts defined in `packages/sdk/src/constants.ts`. The Rust source code is available in the `forks/contracts/` reference repo (auto-cloned via `pnpm install`). Protocol design is documented in the `forks/whitepaper/` reference repo. - -**NervosDAO:** -- Code hash: `0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e` -- Hash type: `type` -- Purpose: Deposit/withdraw CKB with interest (Nervos DAO) -- Managed by: `DaoManager` in `packages/dao/src/dao.ts` -- Constants: `DAO_DEPOSIT_DATA = [0,0,0,0,0,0,0,0]` (8 zero bytes = deposit; non-zero = withdrawal request) -- DAO accumulated rate: extracted from block header at offset 168, size 8 bytes -- Genesis accumulated rate: `AR_0 = 10^16` (used as baseline for iCKB exchange rate) - -**iCKB UDT (xUDT Token):** -- Code hash: `0x50bd8d6680b8b9cf98b73f3c08faf8b2a21914311954118ad6609be6e78a1b95` -- Hash type: `data1` -- Args: `[iCKB_Logic_Hash, 0x00000080]` (0x80000000 = owner mode by input type) -- Token script hash: `0xd485c2271949c232e3f5d46128336c716f90bcbf3cb278696083689fbbcd407a` -- Amount storage: 16 bytes (u128 LE) in cell data -- Purpose: The iCKB token type script (xUDT standard) -- Managed by: `IckbUdtManager` in `packages/core/src/udt.ts` - -**iCKB Logic:** -- Code hash: `0x2a8100ab5990fa055ab1b50891702e1e895c7bd1df6322cd725c1a6115873bd3` -- Hash type: `data1` -- Purpose: Core iCKB deposit/receipt logic (type script) -- Managed by: `LogicManager` in `packages/core/src/logic.ts` -- Contract source: `forks/contracts/scripts/contracts/ickb_logic/` -- Validation rules: - - Empty args required (prevents reuse with different configurations) - - Cell classification: Deposit (iCKB lock + DAO type), Receipt (any lock + iCKB type), UDT (any lock + xUDT type) - - Conservation law: `input_udt + input_receipts = output_udt + input_deposits` - - Deposit size: min 1,000 CKB, max 1,000,000 CKB (unoccupied capacity) - - Soft cap: 100,000 iCKB per deposit; 10% penalty on excess - - Receipt-deposit matching: for each unique deposit amount, deposit count must equal receipt count -- Receipt data format: `[deposit_quantity: u32 LE (4 bytes), deposit_amount: u64 LE (8 bytes)]` = 12 bytes total -- Exchange rate: `iCKB = capacity * AR_0 / AR_m` where AR_m = accumulated rate at deposit block -- Error codes: NotEmptyArgs(5), ScriptMisuse(6), DepositTooSmall(7), DepositTooBig(8), EmptyReceipt(9), ReceiptMismatch(10), AmountMismatch(11), AmountUnreasonablyBig(12) - -**Owned Owner:** -- Code hash: `0xacc79e07d107831feef4c70c9e683dac5644d5993b9cb106dca6e74baa381bd0` -- Hash type: `data1` -- Purpose: Withdrawal ownership tracking (lock script) -- Managed by: `OwnedOwnerManager` in `packages/core/src/owned_owner.ts` -- Contract source: `forks/contracts/scripts/contracts/owned_owner/` -- Design: Solves NervosDAO constraint that deposit lock and withdrawal lock must have equal size -- Mechanism: Owner cell (type=owned_owner) contains `owned_distance: i32 LE` (4 bytes) pointing to its paired owned cell (lock=owned_owner) -- Validation rules: - - Empty args required - - Owned cells must be DAO withdrawal requests (not deposits) - - 1:1 pairing enforced: exactly 1 owner and 1 owned per MetaPoint, in both inputs and outputs - - Cannot be both lock and type simultaneously -- Error codes: NotEmptyArgs(5), NotWithdrawalRequest(6), ScriptMisuse(7), Mismatch(8) - -**Order (Limit Order):** -- Code hash: `0x49dfb6afee5cc8ac4225aeea8cb8928b150caf3cd92fea33750683c74b13254a` -- Hash type: `data1` -- Purpose: On-chain limit orders for CKB/UDT exchange (lock script) -- Managed by: `OrderManager` in `packages/order/src/order.ts` -- Contract source: `forks/contracts/scripts/contracts/limit_order/` -- Lifecycle: Mint (create order + master cell) -> Match (partial/full fill) -> Melt (destroy fulfilled order) -- Order cell data layout (88-89 bytes): - - `[0:16]` UDT amount (u128 LE) - - `[16:20]` Action (u32 LE): 0=Mint, 1=Match - - `[20:52]` TX hash (Mint: all zeros padding) or master outpoint hash (Match) - - `[52:56]` Master distance (Mint: i32 relative offset) or master index (Match: u32 absolute) - - `[56:64]` CKB->UDT ckb_multiplier (u64 LE) - - `[64:72]` CKB->UDT udt_multiplier (u64 LE) - - `[72:80]` UDT->CKB ckb_multiplier (u64 LE) - - `[80:88]` UDT->CKB udt_multiplier (u64 LE) - - `[88:89]` ckb_min_match_log (u8): minimum match = `1 << n`, range 0..=64 -- Validation rules: - - Empty args required - - Mint: output has order + master; padding must be all zeros - - Match: value conservation `in_ckb * ckb_mul + in_udt * udt_mul <= out_ckb * ckb_mul + out_udt * udt_mul` - - Melt: input has order + master; no output - - Concavity check: `c2u.ckb_mul * u2c.udt_mul >= c2u.udt_mul * u2c.ckb_mul` (round-trip cannot lose value) - - DOS prevention: partial matches must meet minimum threshold (`1 << ckb_min_match_log`) - - Order info (ratios, min match, UDT hash) must be immutable across matches - - Cannot modify already-fulfilled orders -- Error codes: NotEmptyArgs(5), DuplicatedMaster(6), InvalidAction(7), NonZeroPadding(8), InvalidRatio(9), InvalidCkbMinMatchLog(10), ConcaveRatio(11), BothRatioNull(12), MissingUdtType(13), SameMaster(14), ScriptMisuse(15), DifferentInfo(16), InvalidMatch(17), DecreasingValue(18), AttemptToChangeFulfilled(19), InsufficientMatch(20), InvalidConfiguration(21) - -**Molecule Schema (`forks/contracts/schemas/encoding.mol`):** -```molecule -struct ReceiptData { deposit_quantity: Uint32, deposit_amount: Uint64 } -struct OwnedOwnerData { owned_distance: Int32 } -struct Ratio { ckb_multiplier: Uint64, udt_multiplier: Uint64 } -struct OrderInfo { ckb_to_udt: Ratio, udt_to_ckb: Ratio, ckb_min_match_log: Uint8 } -struct MintOrderData { padding: Byte32, master_distance: Int32, order_info: OrderInfo } -struct MatchOrderData { master_outpoint: OutPoint, order_info: OrderInfo } -union PartialOrderData { MintOrderData, MatchOrderData } -``` - -**Deployment Groups (Cell Dependencies):** -- Mainnet dep group: TX `0x621a6f38de3b9f453016780edac3b26bfcbfa3e2ecb47c2da275471a5d3ed165` index 0 -- Testnet dep group: TX `0xf7ece4fb33d8378344cab11fcd6a4c6f382fd4207ac921cf5821f30712dcd311` index 0 -- Known bot scripts: one mainnet bot, one testnet bot (lock scripts in `packages/sdk/src/constants.ts`) -- Deployment TX (mainnet): `0xd7309191381f5a8a2904b8a79958a9be2752dbba6871fa193dab6aeb29dc8f44` -- All scripts deployed with zero lock (immutable, non-upgradable) -- Security audit: Scalebit (2024-09-11), no critical vulnerabilities - -**Network configuration:** `IckbSdk.from("mainnet" | "testnet")` in `packages/sdk/src/sdk.ts` selects the appropriate script hashes and dep groups. - -## Monitoring & Observability - -**Error Tracking:** -- None. No Sentry, Rollbar, or similar error tracking service. - -**Logging:** -- JSON structured logs to stdout - - `apps/bot/src/index.ts`: Logs `{ startTime, balance, ratio, actions, txFee, txHash, error, ElapsedSeconds }` each iteration - - `apps/faucet/src/main.ts`: Logs `{ startTime, balance, error, txHash, elapsedSeconds }` each iteration - - `apps/sampler/src/index.ts`: Outputs CSV rows `BlockNumber, Date, Value, Note` -- No log aggregation service - -**Metrics:** -- No metrics service. Bot logs balance and transaction data for manual monitoring. - -## CI/CD & Deployment - -**Hosting:** -- Self-hosted / not specified. No deployment configuration in the repo. -- `apps/interface` produces static build in `apps/interface/dist/` for deployment to any static host -- `apps/interface` has its own `.github/workflows/` directory (likely GitHub Pages deployment, separate repo origin) - -**CI Pipeline:** -- Scripts available: `pnpm test:ci`, `pnpm build:all`, `pnpm lint` -- `@changesets/changelog-github` suggests GitHub Actions integration for releases - -**Publishing:** -- `pnpm change` - Create changeset -- `pnpm version` - Apply changeset versions -- `pnpm publish` - Publish all packages to npm (`pnpm publish -r`) - -## Environment Configuration - -**Required env vars by app:** - -| App | Variable | Required | Description | -|-----|----------|----------|-------------| -| `apps/bot` | `CHAIN` | Yes | Network: "mainnet", "testnet", "devnet" | -| `apps/bot` | `RPC_URL` | No | Custom RPC endpoint (overrides default) | -| `apps/bot` | `BOT_PRIVATE_KEY` | Yes | Hex-encoded private key for signing | -| `apps/bot` | `BOT_SLEEP_INTERVAL` | Yes | Polling interval in seconds (min 1) | -| `apps/faucet` | `ADDRESS` | Yes | Target CKB address for fund transfer | -| `apps/tester` | `CHAIN` | Yes | Network identifier | - -**Env file locations:** -- `apps/bot/env/devnet/.env` - Bot devnet config (exists, not read) -- `apps/tester/env/devnet/.env` - Tester devnet config (exists, not read) -- Loading mechanism: Node.js `--env-file=env/${CHAIN}/.env` flag in start scripts - -## Webhooks & Callbacks - -**Incoming:** -- None. No HTTP servers or webhook endpoints. - -**Outgoing:** -- None. All communication is blockchain RPC calls. - -## CCC Upstream Dependency Details - -CCC (`@ckb-ccc/core`) is the most critical external dependency. Key capabilities used: - -- **Client abstraction:** `ccc.Client`, `ccc.ClientPublicTestnet`, `ccc.ClientPublicMainnet` for blockchain access -- **Transaction building:** `ccc.Transaction`, `ccc.CellInput`, `ccc.CellOutput`, `ccc.CellDep`, `ccc.WitnessArgs` -- **Script handling:** `ccc.Script`, `ccc.KnownScript.NervosDao`, `ccc.Address` -- **Signing:** `ccc.Signer`, `ccc.SignerCkbPrivateKey` -- **Molecule codec:** `mol.Uint64LE`, `mol.Uint128LE`, `mol.Codec`, `mol.Entity` for on-chain data serialization -- **Numeric types:** `ccc.Num`, `ccc.FixedPoint`, `ccc.Hex`, `ccc.fixedPointFrom()`, `ccc.fixedPointToString()` -- **DAO calculations:** `ccc.calcDaoProfit()`, `ccc.calcDaoClaimEpoch()` -- **UDT support:** `ccc.udtBalanceFrom()` (merged upstream from maintainer's PR) -- **Epoch support:** `ccc.Epoch`, `ccc.epochFromHex()`, `ccc.epochToHex()` (merged upstream from maintainer's PR) -- **Async utilities:** `ccc.reduceAsync()` for async iteration with accumulation -- **Cell queries:** `ccc.Cell`, `client.findCells()`, `client.findCellsOnChain()` with filter support - ---- - -*Integration audit: 2026-02-17* diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md deleted file mode 100644 index 711fcfc..0000000 --- a/.planning/codebase/STACK.md +++ /dev/null @@ -1,197 +0,0 @@ -# Technology Stack - -**Analysis Date:** 2026-02-17 - -## Languages - -**Primary:** -- TypeScript 5.9.3 - All source code across packages and apps - -**On-Chain (reference):** -- Rust 2021 edition - On-chain CKB smart contracts in `forks/contracts/` reference repo (3 contracts + shared utils, ~1,163 lines). Built with Capsule v0.10.5, `no_std` + alloc-only runtime, targeting RISC-V. Uses `ckb-std 0.15.3` and `primitive_types` crate for C256 safe math. - -**Secondary:** -- Bash - `forks/forker/record.sh`, `forks/forker/replay.sh` for local fork dev build setup -- JavaScript (CJS) - `.pnpmfile.cjs` for pnpm hook overrides, `prettier.config.cjs` - -## Runtime - -**Environment:** -- Node.js >= 24 (enforced via `engines` in root `package.json`) -- Current environment: v24.13.0 - -**Package Manager:** -- pnpm 10.30.1 (pinned via `packageManager` field with SHA-512 hash in root `package.json`) -- Lockfile: `pnpm-lock.yaml` present -- Workspace protocol: `workspace:*` for internal deps, `catalog:` for shared version pins - -## Frameworks - -**Core:** -- CCC (`@ckb-ccc/core` ^1.12.2) - CKB Common Chains SDK, the primary blockchain interaction library for all new packages. Version pinned via `pnpm-workspace.yaml` catalog. -- React 19.2.0 - Frontend UI framework (`apps/interface` only) -- Vite 6.4.0 - Frontend dev server and build tool (`apps/interface` only) - -**LEGACY and DEPRECATED (still used by apps/bot, apps/tester, apps/interface):** -- `@ckb-lumos/*` 0.23.0 - DEPRECATED Lumos CKB framework. Being replaced by CCC. -- `@ickb/lumos-utils` 1.4.2 - DEPRECATED iCKB Lumos utilities. Being replaced by `@ickb/utils`. -- `@ickb/v1-core` 1.4.2 - DEPRECATED iCKB v1 core logic. Being replaced by `@ickb/core`. - -**Testing:** -- Vitest 3.2.4 - Test runner, configured at root via `vitest.config.mts` -- `@vitest/coverage-v8` 3.2.4 - V8-based coverage - -**Build/Dev:** -- TypeScript 5.9.3 - `tsc` for compilation (all packages/apps use `"build": "tsc"`) -- ESLint 9.39.2 + typescript-eslint 8.55.0 - Linting with strict type-checked rules -- Prettier 3.8.1 + prettier-plugin-organize-imports 4.3.0 - Formatting -- Typedoc 0.28.7 - API documentation generation -- Changesets CLI 2.29.8 - Version management and publishing - -## Key Dependencies - -**Critical (new CCC-based packages):** -- `@ckb-ccc/core` ^1.12.2 - CKB blockchain client, transaction building, signing, cell queries, Molecule codecs. THE foundational dependency for all new code. Used by: `@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`, `@ickb/faucet`, `@ickb/sampler`. - -**Critical (legacy, apps not yet migrated):** -- `@ckb-lumos/*` 0.23.0 - Used by `apps/bot`, `apps/tester`, `apps/interface`. Will be removed when these apps migrate to CCC. -- `@ickb/lumos-utils` 1.4.2 - Legacy iCKB utilities. Used by `apps/bot`, `apps/tester`, `apps/interface`. -- `@ickb/v1-core` 1.4.2 - Legacy iCKB core. Used by `apps/bot`, `apps/tester`, `apps/interface`. - -**Frontend (apps/interface only):** -- `@tanstack/react-query` 5.90.5 - Server-state management and data fetching -- `@ckb-ccc/ccc` ^1.1.21 - CCC full bundle (includes wallet connectors, JoyId signer) -- Tailwind CSS 4.1.14 - Utility-first CSS framework -- `immutable` 4.3.7 - Immutable data structures (used with Lumos TransactionSkeleton) -- `@vitejs/plugin-react` 4.7.0 + `babel-plugin-react-compiler` - React 19 compiler integration -- `@vitejs/plugin-basic-ssl` 1.2.0 - HTTPS in dev mode - -## Monorepo Workspace Structure - -**Workspace definition** (`pnpm-workspace.yaml`): -```yaml -packages: - - packages/* - - apps/* - # @generated begin forker-workspaces — auto-generated by forks/forker/record.sh - - forks/ccc/packages/* - - "!forks/ccc/packages/demo" - - "!forks/ccc/packages/docs" - - "!forks/ccc/packages/examples" - - "!forks/ccc/packages/faucet" - - "!forks/ccc/packages/playground" - - "!forks/ccc/packages/tests" - # @generated end forker-workspaces - -catalog: - '@ckb-ccc/core': ^1.12.2 - '@types/node': ^24.8.1 - -minimumReleaseAge: 1440 -``` - -**Note:** The `forker-workspaces` section between `@generated` markers is auto-generated by `bash forks/forker/record.sh` from `forks/config.json`. Manual edits to that section are overwritten on re-record. - -**Internal dependency graph (new CCC-based packages):** -``` -@ickb/utils <- @ckb-ccc/core -@ickb/dao <- @ckb-ccc/core, @ickb/utils -@ickb/order <- @ckb-ccc/core, @ickb/utils -@ickb/core <- @ckb-ccc/core, @ickb/dao, @ickb/utils -@ickb/sdk <- @ckb-ccc/core, @ickb/core, @ickb/dao, @ickb/order, @ickb/utils -``` - -**Apps dependency split:** -- **CCC-based (new):** `apps/faucet` -> `@ickb/utils`; `apps/sampler` -> `@ickb/core`, `@ickb/utils` -- **Lumos-based (legacy):** `apps/bot`, `apps/tester`, `apps/interface` -> `@ickb/lumos-utils`, `@ickb/v1-core`, `@ckb-lumos/*` - -## Local CCC Dev Build Override Mechanism - -The repo supports using a local development build of CCC for testing unpublished upstream changes. This is controlled by the generic fork management framework (`forks/forker/`) and the CCC-specific configuration (`forks/config.json`): - -**`bash forks/forker/record.sh ccc`:** -- Clones the CCC repo (upstream URL from `forks/config.json`) into `./forks/ccc/` -- Merges refs listed in `forks/config.json` onto a `wip` branch (uses AI Coworker CLI for merge conflict resolution) -- Patches CCC exports for source-level types via `forks/forker/patch.sh` -- Run via: `bash forks/forker/record.sh ccc` -- The `forks/ccc/` directory is gitignored -- Aborts if `forks/ccc/` has pending work (any changes vs pinned commit, diverged HEAD, or untracked files) - -**`.pnpmfile.cjs`:** -- A pnpm `readPackage` hook that auto-discovers all packages in `forks/ccc/packages/*/package.json` -- When `forks/ccc/` exists, overrides all `@ckb-ccc/*` dependency versions in the workspace with `workspace:*` (CCC packages are listed in `pnpm-workspace.yaml`, but catalog specifiers resolve to semver ranges before workspace linking, so the hook forces `workspace:*` to ensure local packages are used) -- Applies to `dependencies`, `devDependencies`, and `optionalDependencies` -- Effect: all workspace packages transparently use the local CCC build instead of npm versions - -**CCC upstream contributions:** The maintainer contributed UDT and Epoch support to CCC upstream (now merged). The local Epoch class has been deleted (replaced by `ccc.Epoch`). Some local UDT handling in `packages/utils/src/udt.ts` may still overlap with features now available in CCC's `@ckb-ccc/udt` package. - -## Configuration - -**TypeScript** (`tsconfig.json`): -- Target: ES2020 -- Module: NodeNext / ModuleResolution: NodeNext -- Strict mode enabled with additional checks: `noUnusedLocals`, `noUnusedParameters`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `noImplicitAny` -- `verbatimModuleSyntax: true` -- `importsNotUsedAsValues: "remove"` -- Packages extend root tsconfig: `rootDir: "src"`, `outDir: "dist"` - -**ESLint** (`eslint.config.mjs`): -- Flat config format (ESLint 9+) -- Base: `eslint.configs.recommended` + `tseslint.configs.strictTypeChecked` + `tseslint.configs.strict` -- Custom rule: `@typescript-eslint/explicit-function-return-type: "error"` -- Ignores: `**/dist/**` -- `apps/interface` has its own `eslint.config.mjs` with React-specific plugins - -**Prettier** (`prettier.config.cjs`): -- Double quotes (`singleQuote: false`) -- Trailing commas: `all` -- Plugin: `prettier-plugin-organize-imports` (auto-sorts imports on format) -- `apps/interface` has a separate `.prettierrc` with `prettier-plugin-tailwindcss` - -**Environment:** -- `apps/bot`: Loads env from `env/${CHAIN}/.env` via Node.js `--env-file=` flag -- `apps/tester`: Same pattern as bot -- `apps/faucet`: Reads `ADDRESS` from env -- `.env` files present at `apps/bot/env/devnet/.env` and `apps/tester/env/devnet/.env` - -**Build:** -- `pnpm build` builds only packages (excludes apps): `pnpm -r --filter !./apps/** build` -- `pnpm build:all` builds everything: `pnpm -r build` -- All packages use `tsc` as build step -- `apps/interface` uses `tsc && vite build` -- `pnpm clean` removes dist dirs; `pnpm clean:deep` also removes node_modules and lockfile - -## Versioning - -**Packages use version `1001.0.0`** (Epoch Semantic Versioning) - All publishable packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) use this version, managed by changesets. - -**Changesets** (`.changeset/config.json`): -- Public access -- GitHub changelog integration linked to `ickb/stack` repo -- Base branch: `master` -- Template syncing via `pnpm sync:template` copies shared config files (`.npmignore`, `tsconfig.json`, `typedoc.json`, `vitest.config.mts`) from `packages/utils` to other packages - -**All packages publish to npm** with `"access": "public"` and `"provenance": true`. - -## Platform Requirements - -**Development:** -- Node.js >= 24 -- pnpm 10.30.1 -- Git (for CCC setup script) -- DevContainer configuration at `.devcontainer/devcontainer.json` - -**Production:** -- `apps/bot`: Node.js CLI, long-running process with `start:loop` (infinite restart with 10s delay) -- `apps/tester`: Node.js CLI, long-running process -- `apps/faucet`: Node.js CLI, one-shot or long-running -- `apps/sampler`: Node.js CLI, outputs CSV to stdout, one-shot -- `apps/interface`: Static SPA built with Vite, deploy as static files - -## Abandoned / Superseded Concepts - -**SmartTransaction** (deleted in Phase 1): Extended `ccc.Transaction` with UDT handler management and header caching. The class and its companion `CapacityManager` were removed entirely. Headers are now fetched inline via CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`) with transparent CCC Client Cache. All manager method signatures now accept `ccc.TransactionLike` and return `ccc.Transaction` directly. - ---- - -*Stack analysis: 2026-02-17* diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md deleted file mode 100644 index ddf5b9d..0000000 --- a/.planning/codebase/STRUCTURE.md +++ /dev/null @@ -1,383 +0,0 @@ -# Codebase Structure - -**Analysis Date:** 2026-02-17 - -## Directory Layout - -``` -/workspaces/stack/ -├── packages/ # NEW CCC-based libraries (replacing Lumos) -│ ├── core/ # iCKB protocol logic (deposits, receipts, ownership) -│ │ └── src/ -│ │ ├── index.ts # Barrel export: cells, entities, logic, owned_owner, udt -│ │ ├── logic.ts # LogicManager class (269 lines) -│ │ ├── owned_owner.ts # OwnedOwnerManager class (239 lines) -│ │ ├── cells.ts # Cell type wrappers (175 lines) -│ │ ├── entities.ts # OwnerData, ReceiptData codec (113 lines) -│ │ └── udt.ts # iCKB UDT value calculations (213 lines) -│ ├── dao/ # Nervos DAO abstraction layer -│ │ └── src/ -│ │ ├── index.ts # Barrel export: cells, dao -│ │ ├── dao.ts # DaoManager class (412 lines) -│ │ └── cells.ts # DaoCell types (180 lines) -│ ├── order/ # Limit order management -│ │ └── src/ -│ │ ├── index.ts # Barrel export: cells, entities, order -│ │ ├── order.ts # OrderManager class (988 lines) -│ │ ├── entities.ts # Info, Ratio, OrderData types (754 lines) -│ │ └── cells.ts # OrderCell, MasterCell, OrderGroup (396 lines) -│ ├── sdk/ # High-level SDK composition -│ │ └── src/ -│ │ ├── index.ts # Barrel export: codec, constants, sdk -│ │ ├── sdk.ts # IckbSdk class (512 lines) -│ │ ├── constants.ts # Script config factory (205 lines) -│ │ └── codec.ts # PoolSnapshot codec (138 lines) -│ └── utils/ # Shared blockchain utilities -│ └── src/ -│ ├── index.ts # Barrel export: codec, heap, udt, utils -│ ├── udt.ts # UDT calculations and handlers (407 lines) -│ ├── utils.ts # Binary search, collectors, etc. (292 lines) -│ ├── codec.ts # CheckedInt32LE codec (21 lines) -│ └── heap.ts # Heap implementation (175 lines) -├── apps/ # Applications -│ ├── bot/ # Order matching daemon (LEGACY - Lumos) -│ │ └── src/ -│ │ └── index.ts # main() entry with order matching loop (897 lines) -│ ├── faucet/ # Testnet CKB distribution (MIGRATED to CCC) -│ │ └── src/ -│ │ ├── index.ts # Entry: imports and calls main() from main.ts -│ │ └── main.ts # main() entry with distribution loop (88 lines) -│ ├── sampler/ # Blockchain state sampling (MIGRATED to CCC) -│ │ └── src/ -│ │ └── index.ts # Direct execution entry (192 lines) -│ ├── tester/ # Order creation simulator (LEGACY - Lumos) -│ │ └── src/ -│ │ └── index.ts # main() entry with test scenarios (469 lines) -│ └── interface/ # React web UI (LEGACY - Lumos) -│ ├── src/ -│ │ ├── main.tsx # startApp(wallet_chain) entry (68 lines) -│ │ ├── App.tsx # Root component with conversion logic (93 lines) -│ │ ├── Connector.tsx # Wallet connection setup (104 lines) -│ │ ├── Form.tsx # User input form (144 lines) -│ │ ├── Action.tsx # Transaction execution (174 lines) -│ │ ├── Dashboard.tsx # Balance display (36 lines) -│ │ ├── Progress.tsx # Loading indicator (42 lines) -│ │ ├── queries.ts # React Query options and state (395 lines) -│ │ ├── transaction.ts # Transaction builders (291 lines) -│ │ ├── utils.ts # Helper utilities (160 lines) -│ │ └── vite-env.d.ts # Vite type definitions -│ └── public/ # Static assets -├── tsgo-filter.sh # Wrapper around tsgo filtering fork diagnostics -├── forks/ # Unified fork management directory -│ ├── .gitignore # Track only .pin/ and config.json -│ ├── config.json # Unified config, all entries keyed by name -│ ├── .pin/ # Committed: computed state per entry -│ │ └── ccc/ -│ │ ├── HEAD # Expected final SHA after full replay -│ │ ├── manifest # Base SHA + merge refs (TSV, one per line) -│ │ ├── res-N.resolution # Conflict resolution for merge step N (counted format) -│ │ └── local-*.patch # Local development patches (applied after merges) -│ ├── forker/ # Gitignored: fork management tool (self-hosting clone) -│ ├── ccc/ # Gitignored: CCC fork clone (auto-replayed) -│ ├── contracts/ # Gitignored: reference clone (Rust on-chain contracts) -│ └── whitepaper/ # Gitignored: reference clone (iCKB protocol design) -├── .planning/ # GSD analysis documents -│ └── codebase/ -│ ├── ARCHITECTURE.md # Architecture and data flows -│ ├── STRUCTURE.md # Directory layout and file locations -│ ├── CONVENTIONS.md # Code style and naming conventions -│ ├── TESTING.md # Testing patterns and frameworks -│ ├── CONCERNS.md # Technical debt and issues -│ ├── STACK.md # Technology stack -│ └── INTEGRATIONS.md # External services and APIs -├── .github/ # GitHub configuration -│ └── workflows/ # CI/CD pipeline definitions -├── .devcontainer/ # Dev container configuration -├── node_modules/ # Installed dependencies (gitignored) -├── .pnpm-store/ # pnpm package cache (gitignored) -├── pnpm-workspace.yaml # Monorepo workspace and catalog definitions -├── package.json # Root workspace scripts and metadata -├── pnpm-lock.yaml # Deterministic lock file (committed) -├── tsconfig.json # Root TypeScript configuration -├── vitest.config.mts # Test framework configuration -├── eslint.config.mjs # ESLint configuration -├── prettier.config.cjs # Code formatter configuration -├── .gitignore # Git exclusions -├── LICENSE # MIT License -├── README.md # Project overview -└── CONTRIBUTING.md # Contribution guidelines -``` - -## Directory Purposes - -**packages/core/src/:** -- Purpose: Core iCKB protocol implementation -- Exports: LogicManager, OwnedOwnerManager, IckbDepositCell, ReceiptCell, WithdrawalGroup, OwnerCell -- Dependencies: @ckb-ccc/core, @ickb/dao, @ickb/utils - -**packages/dao/src/:** -- Purpose: Nervos DAO abstraction layer -- Exports: DaoManager, DaoCell factory -- Key class: `DaoManager` implements ScriptDeps interface -- Methods: `deposit()`, `requestWithdrawal()`, `withdraw()`, `findDeposits()`, `findWithdrawalRequests()` -- Dependencies: @ckb-ccc/core, @ickb/utils - -**packages/order/src/:** -- Purpose: Limit order cell management and matching -- Exports: OrderManager, OrderCell, MasterCell, OrderGroup, Info, Ratio, OrderData -- Key class: `OrderManager` implements ScriptDeps interface -- Methods: `convert()`, `mint()`, `satisfy()`, `melt()`, `findOrders()` -- Key types: `Info` (order metadata), `Ratio` (exchange rate) -- Dependencies: @ckb-ccc/core, @ickb/utils - -**packages/sdk/src/:** -- Purpose: High-level unified SDK for iCKB operations -- Exports: IckbSdk, SystemState, CkbCumulative, PoolSnapshot codec -- Key class: `IckbSdk` with static factory `from()` and instance methods -- Primary methods: `estimate()`, `maturity()`, `request()`, `collect()`, `getL1State()` -- Dependencies: @ckb-ccc/core, @ickb/core, @ickb/dao, @ickb/order, @ickb/utils - -**packages/utils/src/:** -- Purpose: Shared blockchain utilities and primitives -- Exports: UdtHandler, UdtManager, CheckedInt32LE, TransactionHeader, codecs -- Key classes: `UdtManager` (UDT cell management) -- Key helpers: `collect()`, `unique()`, `binarySearch()` -- Dependencies: @ckb-ccc/core - -**apps/bot/src/:** -- Purpose: Automated order matching service -- Status: LEGACY (uses @ickb/v1-core, @ckb-lumos/*, deprecated) -- Entry: `main()` function with infinite loop -- Key operations: State query → order matching → transaction building → signing → broadcast -- Environment variables: CHAIN, RPC_URL, BOT_PRIVATE_KEY, BOT_SLEEP_INTERVAL - -**apps/faucet/src/:** -- Purpose: Testnet CKB distribution from deposit cells -- Status: MIGRATED (uses new packages + CCC) -- Entry: `main.ts` with `main()` function and 2-minute poll loop -- Key operations: Discover faucet funds → build transfer transaction → sign and broadcast -- Environment variables: ADDRESS (recipient address) - -**apps/sampler/src/:** -- Purpose: Blockchain state monitoring and exchange rate sampling -- Status: MIGRATED (uses new packages + CCC) -- Entry: Direct execution from `index.ts` -- Key operations: Periodic state snapshot collection, rate calculation -- Output: CSV format data via rate.csv - -**apps/tester/src/:** -- Purpose: Order creation simulation and testing -- Status: LEGACY (uses @ickb/v1-core, @ckb-lumos/*, deprecated) -- Entry: `main()` function with test scenarios -- Key operations: Simulate user order creation, validate responses - -**apps/interface/src/:** -- Purpose: Web UI for iCKB operations (React application) -- Status: LEGACY (uses @ickb/v1-core, @ckb-lumos/*, deprecated) -- Entry: `main.tsx` with `startApp(wallet_chain)` function -- Component tree: Connector → App → Form/Dashboard/Action -- Data flow: React Query for L1 state, @ickb/v1-core for TX building -- Styling: TailwindCSS with inline classes - -**forks/:** -- Purpose: Unified fork management directory (managed forks and reference-only clones) -- `config.json`: Single source of truth for all entries, keyed by name -- `.pin//`: Committed pin state per entry (manifest + counted resolutions + local patches) -- `forker/`: Gitignored self-hosting clone of the fork management tool -- `ccc/`: Gitignored CCC fork clone, auto-replayed from `.pin/ccc/` on `pnpm install` -- `contracts/`, `whitepaper/`: Gitignored reference clones, shallow-cloned on `pnpm install` -- Activation: `.pnpmfile.cjs` bootstraps forker, replays pins, and overrides @ckb-ccc/* deps - -**.planning/codebase/:** -- Purpose: GSD codebase analysis documents -- Contents: ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md, STACK.md, INTEGRATIONS.md -- Usage: Read by GSD orchestrator for phase planning and code generation - -## Key File Locations - -**Entry Points:** -- SDK: `packages/sdk/src/sdk.ts` → `IckbSdk` class with static `from()` factory -- Faucet app: `apps/faucet/src/main.ts` → `main()` async function -- Bot app: `apps/bot/src/index.ts` → `main()` async function -- Interface app: `apps/interface/src/main.tsx` → `startApp(wallet_chain: string)` function -- Sampler app: `apps/sampler/src/index.ts` → Direct execution entry -- Tester app: `apps/tester/src/index.ts` → `main()` async function - -**Configuration Files:** -- Monorepo: `pnpm-workspace.yaml` (workspace definition + catalog) -- Root scripts: `package.json` (build/test/lint/dev commands) -- TypeScript: `tsconfig.json` (ES2020 target, strict mode) -- Tests: `vitest.config.mts` (test discovery and coverage) -- Linting: `eslint.config.mjs` (ESLint rules) -- Formatting: `prettier.config.cjs` (code style) - -**Core Domain Logic:** -- Deposits: `packages/core/src/logic.ts` → `LogicManager` class (269 lines) -- Orders: `packages/order/src/order.ts` → `OrderManager` class (988 lines) -- DAO: `packages/dao/src/dao.ts` → `DaoManager` class (412 lines) -- UDT: `packages/utils/src/udt.ts` → `UdtHandler` interface + `UdtManager` class (407 lines) - -**Type Definitions:** -- Order entities: `packages/order/src/entities.ts` (Info, Ratio, OrderData) — 754 lines -- Core entities: `packages/core/src/entities.ts` (OwnerData, ReceiptData) — 113 lines -- Cell wrappers: `packages/{core,dao,order}/src/cells.ts` (DaoCell, IckbDepositCell, etc.) - -## Naming Conventions - -**Files:** -- Source: `*.ts` for TypeScript, `*.tsx` for React components -- Compiled: `dist/` directory (generated, gitignored) -- Type definitions: Auto-generated from source via `declaration: true` -- Tests: Not currently present; would use `*.test.ts` or `*.spec.ts` pattern - -**Directories:** -- Packages: kebab-case (`core`, `dao`, `order`, `sdk`, `utils`) -- Apps: kebab-case (`bot`, `faucet`, `sampler`, `tester`, `interface`) -- Source: Always `src/` for both packages and apps -- Output: Always `dist/` after compilation - -**Exports:** -- Barrel files: `index.ts` re-exports all public symbols -- Pattern: `export * from "./module.js"` (using `.js` extension for ESM) -- No default exports; all named exports -- Types and functions exported at package level via index - -**Classes and Functions:** -- Classes: PascalCase (e.g., `IckbSdk`, `LogicManager`, `DaoManager`, `OrderManager`) -- Manager suffix: Consistently applied to manager classes -- Instance methods: camelCase (e.g., `deposit()`, `mint()`, `getL1State()`) -- Static methods: camelCase on class (e.g., `IckbSdk.from()`, `IckbSdk.estimate()`) -- Private methods: camelCase prefixed with underscore (e.g., `_getCkb()`) - -**Interfaces and Types:** -- Interfaces: PascalCase (e.g., `DaoCell`, `OrderCell`, `ValueComponents`) -- Input-like types: Suffix with -Like (e.g., `InfoLike`, `OwnerDataLike`) -- Readonly types: No prefix; immutability expressed via readonly properties -- Type unions: PascalCase (e.g., `SystemState`, `OrderGroup`, `L1StateType`) - -## Where to Add New Code - -**New Blockchain Operation (e.g., new order type):** -- Domain package location: `packages/{appropriate-domain}/src/{feature}.ts` - - Order-related: `packages/order/src/` - - DAO-related: `packages/dao/src/` - - iCKB-specific: `packages/core/src/` -- Manager method: Add to appropriate Manager class -- Type export: Add to barrel export in `packages/{package}/src/index.ts` -- SDK integration: If cross-domain, add to `IckbSdk` in `packages/sdk/src/sdk.ts` - -**New React Component (e.g., new UI page):** -- Location: `apps/interface/src/{ComponentName}.tsx` -- Pattern: Functional component with React hooks -- Data fetching: Add query factory to `apps/interface/src/queries.ts` -- Styling: TailwindCSS classes inline; no separate CSS files -- State: Use React hooks + React Query for async state - -**New CLI App (e.g., new service daemon):** -- Structure: Create `apps/{app-name}/` directory -- Template: Copy structure from existing app (faucet or sampler) -- Required files: - - `package.json` with scripts and dependencies - - `src/index.ts` as entry point (export main function if needed) - - `src/main.ts` if index.ts re-exports - - `env/{CHAIN}/.env` if environment-specific config needed -- Registration: Auto-detected by pnpm-workspace.yaml pattern matching - -**New Utility Function:** -- Shared/generic: `packages/utils/src/{category}.ts` -- Domain-specific: Place in appropriate domain package `src/{category}.ts` -- Export: Add to barrel in `src/index.ts` with `export * from "./{category}.js"` -- Import pattern: Use `.js` extensions in ESM exports for compatibility - -**New Manager Class:** -- Location: `packages/{domain}/src/{manager-name}.ts` -- Pattern: Implement `ScriptDeps` interface if handling scripts: - ```typescript - export class FeatureManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - ) {} - // ... methods - } - ``` -- Transaction methods: Accept `ccc.TransactionLike`, return `ccc.Transaction`, call `.addCellDeps()`, `.addInput()`, `.addOutput()` -- Finding methods: Use async generators for lazy cell discovery -- Type checkers: Implement `isFoo(cell)` methods for type verification - -**Dependencies:** -- Internal package: `"@ickb/package": "workspace:*"` in package.json -- Internal CCC (local dev): Automatic via `.pnpmfile.cjs` override when `forks/ccc/` exists -- External package: `pnpm add @vendor/package` from workspace root -- Catalog versions: Reference via `"@vendor/package": "catalog:"` in pnpm-workspace.yaml - -**forks/contracts/ (reference entry):** -- Purpose: Rust on-chain smart contracts for the iCKB protocol (3 production contracts + shared utils) -- Auto-cloned via `pnpm install` (git-ignored, shallow clone) -- Key paths: - - `scripts/contracts/ickb_logic/` - Type script: iCKB UDT minting, deposit/receipt validation, conservation law - - `scripts/contracts/limit_order/` - Lock script: peer-to-peer limit order matching (mint/match/melt lifecycle) - - `scripts/contracts/owned_owner/` - Lock script: owner-owned cell pairing for DAO withdrawal delegation - - `scripts/contracts/utils/` - Shared: DAO helpers, C256 safe math, MetaPoint, cell type classification - - `schemas/encoding.mol` - Molecule schema definitions (canonical data format that TS codecs must match) - - `scripts/deployment/` - Network configs (devnet/testnet/mainnet) -- Build: Capsule v0.10.5, Rust 2021, `no_std` + alloc-only, RISC-V target -- Audit: Scalebit (2024-09-11) - -**forks/whitepaper/ (reference entry):** -- Purpose: iCKB protocol design specification -- Auto-cloned via `pnpm install` (git-ignored, shallow clone) -- Key files: - - `README.md` (~49KB) - Complete protocol specification: deposit/withdrawal phases, exchange rate mechanics, soft cap penalty, pooled deposit model, ancillary scripts (owned owner, limit order), deployment details, attack mitigations - - `2024_overview.md` - Project timeline and milestones -- Key concepts: 2-phase deposit/withdrawal, `iCKB = capacity * AR_0 / AR_m`, 100k iCKB soft cap with 10% excess penalty, non-upgradable deployment, NervosDAO illiquidity solution - -## Special Directories - -**forks/forker/:** -- Purpose: Generic fork management framework for deterministic, conflict-free builds -- System: Record/replay mechanism using pins (manifest + counted resolutions + local patches) -- All scripts accept an entry name as their first argument (e.g., `ccc`) -- Commands (using `ccc` as example): - - Record: `bash forks/forker/record.sh ccc` (requires AI Coworker CLI) - - Status: `bash forks/forker/status.sh ccc` (check for pending work in clone) - - Save: `bash forks/forker/save.sh ccc [description]` (capture local work as patch in .pin/) - - Push: `bash forks/forker/push.sh ccc` (cherry-pick commits onto a PR branch) - - Rebuild: `pnpm install` (automatic when .pin/ exists but clone does not) - - Clean (re-replay): `bash forks/forker/clean.sh ccc && pnpm install` (guarded) - - Reset (published): `bash forks/forker/reset.sh ccc && pnpm install` (guarded) - -**forks/ccc/:** -- Purpose: CCC fork clone for local development against unpublished upstream changes -- Configuration: `forks/config.json` (unified config, entry keyed by `ccc`) -- Pin state: `forks/.pin/ccc/` (committed manifest + counted resolutions + local patches) -- Clone: `forks/ccc/` (gitignored, generated from pins; auto-replayed on `pnpm install`) -- Activation: `.pnpmfile.cjs` hook triggers `forks/forker/replay.sh` and overrides package resolution - -**node_modules/:** -- Purpose: Installed npm/pnpm dependencies -- Auto-generated: Yes (via `pnpm install`) -- Committed: No (in .gitignore) -- Management: pnpm handles with pnpm-lock.yaml - -**dist/:** -- Purpose: Compiled TypeScript output -- Auto-generated: Yes (via `pnpm build`) -- Committed: No (in .gitignore) -- Structure: Mirrors src/ with `.js`, `.d.ts`, and `.map` files -- Cleanup: `pnpm clean` removes all dist/ directories - -**.github/workflows/:** -- Purpose: GitHub Actions CI/CD pipelines -- Committed: Yes -- Workflows: Build, test, and publish on push/PR - -**.planning/codebase/:** -- Purpose: GSD analysis documents for orchestrator reference -- Generated: Yes (by `gsd:map-codebase` command) -- Committed: Yes -- Usage: `gsd:plan-phase` loads relevant docs for code generation guidance - ---- - -*Structure analysis: 2026-02-17* diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md deleted file mode 100644 index 5acab03..0000000 --- a/.planning/codebase/TESTING.md +++ /dev/null @@ -1,379 +0,0 @@ -# Testing Patterns - -**Analysis Date:** 2026-02-17 - -## Important Context - -**Legacy vs. New code:** -- `@ickb/lumos-utils@1.4.2` and `@ickb/v1-core@1.4.2` are **LEGACY and DEPRECATED**. They have no tests in this monorepo (they were published separately). -- The `packages/` directory contains the **NEW replacement libraries** -- these are the packages that need tests. -- All `@ckb-lumos/*` packages are **DEPRECATED** -- do not write tests that depend on Lumos. -- CCC PRs for UDT and Epochs have been **MERGED** upstream. -- `SmartTransaction` was **ABANDONED** -- do not expand its test coverage; it exists in `packages/utils/src/transaction.ts` but header caching now uses CCC's client cache. - -**Current test status:** No `.test.ts` files exist yet in the `packages/` or `apps/` source directories. Vitest is fully configured and ready. The CI pipeline runs `pnpm check` which includes `pnpm test:ci`, but with no test files `vitest run` passes vacuously. Writing tests is a greenfield effort. - -## Test Framework - -**Runner:** -- Vitest 3.2.4 -- Root config: `vitest.config.mts` -- Per-package config: `packages/*/vitest.config.mts` - -**Assertion Library:** -- Vitest native assertions via `expect()` - -**Coverage Tool:** -- `@vitest/coverage-v8` 3.2.4 - -**Run Commands:** -```bash -pnpm test # Run all tests in watch mode (packages/* only) -pnpm test:ci # Run all tests once (CI mode) -pnpm test:cov # Run tests with V8 coverage report -``` - -Per-package (from within a package directory): -```bash -pnpm test # Run tests for this package in watch mode -pnpm test:ci # Run tests for this package once -``` - -## Test Configuration - -**Root `vitest.config.mts`:** -```typescript -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - projects: ["packages/*"], - coverage: { - include: ["packages/*"], - }, - }, -}); -``` - -**Per-package `vitest.config.mts` (identical for all packages):** -```typescript -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - include: ["src/**/*.test.ts"], - coverage: { - include: ["src/**/*.ts"], - }, - }, -}); -``` - -**Key configuration details:** -- Tests run via Vitest workspace projects -- root config delegates to per-package configs -- Test files must match `src/**/*.test.ts` (co-located with source) -- Coverage tracks all `src/**/*.ts` files -- Apps (`apps/*`) do NOT have vitest project entries in the root config -- tests are packages-only -- Each package's `package.json` has `"test": "vitest"` and `"test:ci": "vitest run"` scripts - -## Test File Organization - -**Location:** -- Co-located with source files inside `packages/*/src/` -- Tests live alongside the code they test - -**Naming:** -- Use `.test.ts` suffix (not `.spec.ts`) -- Name should match the source file: `codec.ts` -> `codec.test.ts`, `heap.ts` -> `heap.test.ts` - -**Expected structure when adding tests:** -``` -packages/utils/ -├── src/ -│ ├── capacity.ts -│ ├── capacity.test.ts # <-- tests go here -│ ├── codec.ts -│ ├── codec.test.ts # <-- tests go here -│ ├── heap.ts -│ ├── heap.test.ts # <-- tests go here -│ ├── index.ts -│ ├── transaction.ts -│ ├── udt.ts -│ ├── utils.ts -│ └── utils.test.ts # <-- tests go here -└── vitest.config.mts -``` - -## Test Structure - -**Suite Organization:** -Use `describe` for grouping by class or function, `it` or `test` for individual behaviors: - -```typescript -import { describe, expect, it } from "vitest"; -import { Ratio } from "./entities.js"; - -describe("Ratio", () => { - describe("from", () => { - it("creates from plain object", () => { - const ratio = Ratio.from({ ckbScale: 3n, udtScale: 4n }); - expect(ratio.ckbScale).toBe(3n); - expect(ratio.udtScale).toBe(4n); - }); - - it("short-circuits on Ratio instance", () => { - const ratio = new Ratio(10n, 20n); - expect(Ratio.from(ratio)).toBe(ratio); - }); - }); - - describe("validate", () => { - it("accepts populated ratio", () => { - const r = new Ratio(100n, 200n); - expect(() => r.validate()).not.toThrow(); - expect(r.isValid()).toBe(true); - }); - - it("accepts empty ratio", () => { - const r = Ratio.empty(); - expect(() => r.validate()).not.toThrow(); - expect(r.isValid()).toBe(true); - }); - - it("rejects half-populated ratio", () => { - const r = new Ratio(100n, 0n); - expect(() => r.validate()).toThrow("not empty, not populated"); - expect(r.isValid()).toBe(false); - }); - }); -}); -``` - -**Conventions:** -- Top-level `describe()` per class or exported function -- Nested `describe()` per method being tested -- Each `it()` tests a single behavior or edge case -- Test names describe the expected behavior, not the implementation -- Use data-driven parameterized tests for exhaustive case coverage - -## Parameterized / Data-Driven Tests - -For functions with many edge cases, use array-based parameterization: - -```typescript -describe("binarySearch", () => { - const cases: [number, (i: number) => boolean, number][] = [ - [10, (i) => i > 5, 6], - [10, (i) => i >= 0, 0], - [10, () => false, 10], - [0, () => true, 0], - ]; - - cases.forEach(([n, f, expected]) => - it(`binarySearch(${n}, f) returns ${expected}`, () => { - expect(binarySearch(n, f)).toBe(expected); - }), - ); -}); -``` - -## Mocking - -**Framework:** Vitest built-in mocking via `vi.fn()`, `vi.mock()`, `vi.spyOn()` - -**What to Mock:** -- `ccc.Client` methods when testing code that calls RPC (e.g., `getHeaderByNumber`, `getTipHeader`, `findCells`) -- Network I/O in manager classes (`DaoManager`, `LogicManager`, `OrderManager`) -- Never mock the molecule codec layer -- test encode/decode with real data - -**What NOT to Mock:** -- Pure computation functions (`binarySearch`, `gcd`, `shuffle`, `min`, `max`, `sum`) -- Epoch arithmetic (`Epoch.from`, `add`, `sub`, `compare`) -- Codec encode/decode (`Ratio.encode`, `OrderData.decode`, `CheckedInt32LE`) -- Entity validation (`validate`, `isValid`) - -**Suggested mocking pattern for CCC client:** -```typescript -import { vi, describe, it, expect } from "vitest"; - -const mockClient = { - getHeaderByNumber: vi.fn(), - getTipHeader: vi.fn(), - findCells: vi.fn(async function* () {}), - findCellsOnChain: vi.fn(async function* () {}), -} as unknown as ccc.Client; -``` - -## Fixtures and Factories - -**Test Data:** -- Define inline within test files -- Use real blockchain-style hex strings and bigint values: -```typescript -const testCell = ccc.Cell.from({ - outPoint: { txHash: "0x" + "ab".repeat(32), index: 0 }, - cellOutput: { - capacity: ccc.fixedPointFrom("1000"), - lock: ccc.Script.from({ codeHash: "0x" + "00".repeat(32), hashType: "type", args: "0x" }), - }, - outputData: "0x", -}); -``` - -**No separate fixtures directory.** Keep test data close to test logic. - -**Factory helpers:** If a test file needs repeated construction, define a local factory function: -```typescript -function makeRatio(ckb: bigint, udt: bigint): Ratio { - return new Ratio(ckb, udt); -} -``` - -## Coverage - -**Requirements:** Not currently enforced. No minimum threshold configured. - -**View Coverage:** -```bash -pnpm test:cov # Generates V8 coverage report -``` - -**Coverage scope:** -- Root config: `packages/*` directories -- Per-package: `src/**/*.ts` files -- Apps are excluded from coverage - -## Test Types - -**Unit Tests (primary focus for `packages/`):** -- Scope: Individual classes, functions, pure logic -- Location: `packages/*/src/*.test.ts` -- Priority targets for new tests: - 1. `packages/utils/src/utils.ts` - `binarySearch`, `asyncBinarySearch`, `gcd`, `min`, `max`, `sum`, `hexFrom`, `isHex`, `shuffle` - 2. `packages/utils/src/codec.ts` - `CheckedInt32LE` encode/decode - 3. `packages/utils/src/heap.ts` - `MinHeap` operations (push, pop, remove, fix) - 5. `packages/order/src/entities.ts` - `Ratio`, `Info`, `Relative`, `OrderData` encode/decode/validate - 6. `packages/order/src/cells.ts` - `OrderCell.mustFrom`, `OrderCell.tryFrom`, `OrderGroup` - 7. `packages/dao/src/dao.ts` - `DaoManager.isDeposit`, `isWithdrawalRequest` - 8. `packages/core/src/entities.ts` - Entity encode/decode roundtrips - -**Integration Tests:** -- Scope: Multi-component interactions requiring a mock CCC client -- Example: `LogicManager.deposit()` combining DaoManager + UdtHandler -- Example: `IckbSdk.estimate()` combining exchange ratios with order info - -**Contract-Alignment Tests (critical):** -- Scope: Verify TS logic produces identical results to Rust contract validation -- Priority targets: - 1. Exchange rate: `iCKB = capacity * AR_0 / AR_m` with soft cap penalty -- must match `forks/contracts/scripts/contracts/ickb_logic/src/entry.rs` `deposit_to_ickb()` - 2. Molecule encoding: `ReceiptData`, `OwnedOwnerData`, `Ratio`, `OrderInfo`, `MintOrderData`, `MatchOrderData` -- must match `forks/contracts/schemas/encoding.mol` - 3. Order value conservation: `in_ckb * ckb_mul + in_udt * udt_mul <= out_ckb * ckb_mul + out_udt * udt_mul` -- must match `forks/contracts/scripts/contracts/limit_order/src/entry.rs` `validate()` - 4. Concavity check: `c2u.ckb_mul * u2c.udt_mul >= c2u.udt_mul * u2c.ckb_mul` -- must match limit_order contract - 5. Deposit size bounds: min 1,000 CKB, max 1,000,000 CKB unoccupied capacity - 6. Owned owner distance calculation: TS MetaPoint arithmetic must match contract's `extract_owned_metapoint()` -- Approach: Use known input/output vectors derived from the Rust contract logic or construct test cases from the Molecule schema - -**E2E Tests:** -- Not applicable -- apps interact with live blockchain nodes -- Integration testing of apps happens via manual testing against devnet/testnet - -## Common Patterns - -**Testing validate/isValid pairs:** -```typescript -describe("Ratio", () => { - it("validates populated ratio", () => { - const r = new Ratio(100n, 200n); - expect(() => r.validate()).not.toThrow(); - expect(r.isValid()).toBe(true); - }); - - it("validates empty ratio", () => { - const r = Ratio.empty(); - expect(() => r.validate()).not.toThrow(); - expect(r.isValid()).toBe(true); - }); - - it("rejects half-populated ratio", () => { - const r = new Ratio(100n, 0n); - expect(() => r.validate()).toThrow("not empty, not populated"); - expect(r.isValid()).toBe(false); - }); -}); -``` - -**Testing codec roundtrips:** -```typescript -describe("CheckedInt32LE", () => { - it("roundtrips valid values", () => { - const values = [0, 1, -1, 2147483647, -2147483648]; - for (const v of values) { - const encoded = CheckedInt32LE.encode(v); - const decoded = CheckedInt32LE.decode(encoded); - expect(decoded).toBe(v); - } - }); - - it("rejects out-of-bounds values", () => { - expect(() => CheckedInt32LE.encode(2147483648)).toThrow("out of int32 bounds"); - expect(() => CheckedInt32LE.encode(-2147483649)).toThrow("out of int32 bounds"); - }); -}); -``` - -**Testing async generators:** -```typescript -import { collect } from "./utils.js"; - -it("collects async iterable into array", async () => { - async function* gen(): AsyncGenerator { - yield 1; - yield 2; - yield 3; - } - const result = await collect(gen()); - expect(result).toEqual([1, 2, 3]); -}); -``` - -**Testing entity `from()` short-circuit:** -```typescript -it("returns same instance when already correct type", () => { - const original = new Ratio(10n, 20n); - expect(Ratio.from(original)).toBe(original); // identity check -}); -``` - -**Testing comparison methods:** -```typescript -describe("Ratio.compare", () => { - it("compares by cross-multiplication", () => { - const a = new Ratio(3n, 4n); // 3/4 - const b = new Ratio(2n, 3n); // 2/3 - expect(a.compare(b)).toBeGreaterThan(0); // 3*3 - 2*4 = 1 - expect(b.compare(a)).toBeLessThan(0); - }); - - it("returns 0 for equal ratios", () => { - const a = new Ratio(1n, 2n); - const b = new Ratio(1n, 2n); - expect(a.compare(b)).toBe(0); - }); -}); -``` - -## CI Integration - -**Current state in `.github/workflows/check.yaml`:** -```yaml -- name: Check (lint, build and test) - run: pnpm check -``` - -The `pnpm check` script runs: `pnpm clean:deep && pnpm install && pnpm lint && pnpm build:all && pnpm test:ci`. Tests are included but with no test files, `vitest run` passes vacuously. - -**CI runs on:** `[pull_request, push]` events, `ubuntu-latest`, Node.js 24, pnpm. - ---- - -*Testing analysis: 2026-02-17* diff --git a/.planning/config.json b/.planning/config.json deleted file mode 100644 index a066169..0000000 --- a/.planning/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "mode": "interactive", - "depth": "comprehensive", - "parallelization": false, - "commit_docs": true, - "model_profile": "quality", - "workflow": { - "research": true, - "plan_check": true, - "verifier": true - } -} diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-PLAN.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-PLAN.md deleted file mode 100644 index 962b7f3..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-PLAN.md +++ /dev/null @@ -1,263 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - forks/ccc/packages/core/src/ckb/transactionErrors.ts - - forks/ccc/packages/core/src/ckb/transaction.ts - - forks/ccc/packages/core/src/ckb/index.ts - - forks/.pin/ccc/ - - packages/dao/src/dao.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts - - packages/utils/src/transaction.ts -autonomous: true -requirements: - - SMTX-06 - -must_haves: - truths: - - "A single CCC utility `assertDaoOutputLimit` exists in CCC core that checks both inputs and outputs for DAO type script when outputs > 64" - - "All 7 scattered inline DAO output checks across dao/core/utils are replaced with calls to `assertDaoOutputLimit`" - - "The `ErrorNervosDaoOutputLimit` error class exists in CCC `transactionErrors.ts` with count and limit fields" - - "`pnpm check:full` passes after DAO check consolidation" - artifacts: - - path: "forks/ccc/packages/core/src/ckb/transactionErrors.ts" - provides: "ErrorNervosDaoOutputLimit error class" - contains: "ErrorNervosDaoOutputLimit" - - path: "forks/ccc/packages/core/src/ckb/transaction.ts" - provides: "assertDaoOutputLimit utility function and completeFee safety net" - contains: "assertDaoOutputLimit" - key_links: - - from: "packages/dao/src/dao.ts" - to: "forks/ccc/packages/core/src/ckb/transaction.ts" - via: "import and call assertDaoOutputLimit" - pattern: "assertDaoOutputLimit" - - from: "packages/core/src/logic.ts" - to: "forks/ccc/packages/core/src/ckb/transaction.ts" - via: "import and call assertDaoOutputLimit" - pattern: "assertDaoOutputLimit" - - from: "packages/core/src/owned_owner.ts" - to: "forks/ccc/packages/core/src/ckb/transaction.ts" - via: "import and call assertDaoOutputLimit" - pattern: "assertDaoOutputLimit" ---- - - -Build the 64-output NervosDAO limit check as a CCC core utility and replace all 7 scattered inline checks across the iCKB packages with calls to this centralized utility. - -Purpose: Consolidate duplicated DAO output limit logic into a single source of truth in CCC core, preparing for SmartTransaction deletion by removing one of its responsibilities. This is the first feature-slice step (purely additive, nothing breaks). - -Output: `ErrorNervosDaoOutputLimit` error class + `assertDaoOutputLimit` utility in CCC core; all iCKB packages calling the utility instead of inline checks; forks/ccc pins recorded. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md -@.planning/codebase/ARCHITECTURE.md - -Key source files to read: -@forks/ccc/packages/core/src/ckb/transactionErrors.ts (error class patterns) -@forks/ccc/packages/core/src/ckb/transaction.ts (completeFee method, where safety net goes) -@forks/ccc/packages/core/src/ckb/index.ts (barrel exports) -@packages/utils/src/transaction.ts (SmartTransaction.completeFee with DAO check at lines 85-95) -@packages/dao/src/dao.ts (DaoManager with 3 DAO checks at lines 100, 174, 245) -@packages/core/src/logic.ts (LogicManager.deposit with DAO check at line 106) -@packages/core/src/owned_owner.ts (OwnedOwnerManager with 2 DAO checks at lines 104, 146) - - - - - - Task 1: Build ErrorNervosDaoOutputLimit and assertDaoOutputLimit in CCC core - - forks/ccc/packages/core/src/ckb/transactionErrors.ts - forks/ccc/packages/core/src/ckb/transaction.ts - forks/ccc/packages/core/src/ckb/index.ts - - -**Step 1: Add error class to transactionErrors.ts** - -Read `forks/ccc/packages/core/src/ckb/transactionErrors.ts`. Add `ErrorNervosDaoOutputLimit` following the existing `ErrorTransactionInsufficientCapacity` pattern: - -```typescript -export class ErrorNervosDaoOutputLimit extends Error { - public readonly count: number; - public readonly limit: number; - - constructor(count: number) { - super( - `NervosDAO transaction has ${count} output cells, exceeding the limit of 64`, - ); - this.count = count; - this.limit = 64; - } -} -``` - -**Step 2: Add assertDaoOutputLimit to transaction.ts** - -Read `forks/ccc/packages/core/src/ckb/transaction.ts`. Add the standalone utility function as a module-level export (NOT a method on Transaction). Place it after the Transaction class definition. Import `ErrorNervosDaoOutputLimit` from `./transactionErrors.js`, `KnownScript` from the appropriate module, and `Script` if not already imported: - -```typescript -/** - * Asserts that a NervosDAO transaction does not exceed the 64-output limit. - * Auto-resolves unresolved inputs (populating CellInput.cellOutput as a side effect). - * Only checks when outputs > 64 AND at least one input or output has the DAO type script. - * - * @param tx - The transaction to check - * @param client - CKB client for resolving the NervosDAO script and input cell info - * @throws ErrorNervosDaoOutputLimit if limit exceeded - */ -export async function assertDaoOutputLimit( - tx: Transaction, - client: Client, -): Promise { - if (tx.outputs.length <= 64) return; - - const { codeHash, hashType } = await client.getKnownScript( - KnownScript.NervosDao, - ); - const dao = Script.from({ codeHash, hashType, args: "0x" }); - - // Auto-resolve unresolved inputs - for (const input of tx.inputs) { - await input.completeExtraInfos(client); - } - - const isDaoTx = - tx.inputs.some((i) => i.cellOutput?.type?.eq(dao)) || - tx.outputs.some((o) => o.type?.eq(dao)); - - if (isDaoTx) { - throw new ErrorNervosDaoOutputLimit(tx.outputs.length); - } -} -``` - -IMPORTANT: Use full `Script.eq()` comparison (codeHash + hashType + args), not just codeHash comparison. - -**Step 3: Add completeFee safety net** - -In the `completeFee` method of the Transaction class (around line 2183), add a call to `assertDaoOutputLimit(this, from.client)` near the end of the method, before returning. Read the method carefully to find the right insertion point -- it should be called after all outputs have been finalized but before the final return. The client is available as `from.client` (Signer has a `client` property). - -**Step 4: Export from barrel** - -Read `forks/ccc/packages/core/src/ckb/index.ts`. Add exports for `ErrorNervosDaoOutputLimit` (from `./transactionErrors.js`) and `assertDaoOutputLimit` (from `./transaction.js`). Follow existing export patterns in the file. - -**Step 5: Record forks/ccc pins** - -Run: `bash forks/forker/record.sh ccc` - -This updates `forks/.pin/ccc/` to reflect the new CCC state. - -Verify: `bash forks/forker/status.sh ccc` should exit 0 (no pending work). - - -1. `bash forks/forker/status.sh ccc` exits 0 -2. `grep -r "ErrorNervosDaoOutputLimit" forks/ccc/packages/core/src/ckb/transactionErrors.ts` finds the class -3. `grep -r "assertDaoOutputLimit" forks/ccc/packages/core/src/ckb/transaction.ts` finds the function -4. `pnpm check:full` passes (purely additive change, nothing should break) - - -ErrorNervosDaoOutputLimit error class exists in CCC transactionErrors.ts with count and limit fields. assertDaoOutputLimit standalone utility exists in CCC transaction.ts using full Script.eq() comparison with args: "0x". completeFee has a safety net call to assertDaoOutputLimit. Both are exported from the CCC barrel. Pins are recorded. - - - - - Task 2: Replace all 7 scattered DAO checks with assertDaoOutputLimit calls - - packages/dao/src/dao.ts - packages/core/src/logic.ts - packages/core/src/owned_owner.ts - packages/utils/src/transaction.ts - - -Replace all 7 inline `if (tx.outputs.length > 64)` DAO checks with calls to `await assertDaoOutputLimit(tx, client)`. This requires making the containing methods async and adding a `client` parameter. - -**6 sync methods that need to become async with client parameter:** - -Read each file. For each method listed below: -1. Add `client: ccc.Client` parameter (add as the LAST parameter, after any existing `options` parameter -- or as a required parameter before options if options is the last param) -2. Change return type from `void` to `Promise` (method becomes async) -3. Add `async` keyword to the method -4. Replace the inline check with `await assertDaoOutputLimit(tx, client);` -5. Import `assertDaoOutputLimit` from `@ckb-ccc/core` (or `ccc` namespace) at the top of each file - -**packages/dao/src/dao.ts** (3 checks): -- `deposit()` at line 76 -- replace check at line 100-102 with `await assertDaoOutputLimit(tx, client);` -- `requestWithdrawal()` at line 119 -- replace check at line 174-176 with `await assertDaoOutputLimit(tx, client);` -- `withdraw()` at line 189 -- replace check at line 245-247 with `await assertDaoOutputLimit(tx, client);` - -Note: `requestWithdrawal` and `withdraw` ALREADY have `client` as a parameter (they call `getHeader`). `deposit` does NOT currently have `client` -- add it. - -**packages/core/src/logic.ts** (1 check): -- `deposit()` at line 68 -- replace check at line 106-108 with `await assertDaoOutputLimit(tx, client);` - -Note: `deposit` does NOT currently have `client` -- add it. The method calls `this.daoManager.deposit()` which also needs client now. Since that call will need to be awaited after this change, the cascading async is intentional. - -**packages/core/src/owned_owner.ts** (2 checks): -- `requestWithdrawal()` at line 69 -- replace check at line 104-106 with `await assertDaoOutputLimit(tx, client);` -- `withdraw()` at line 118 -- replace check at line 146-148 with `await assertDaoOutputLimit(tx, client);` - -Note: Both methods DO NOT currently have `client` -- add it. The inner `this.daoManager.requestWithdrawal()` and `this.daoManager.withdraw()` calls already pass client (they need it for header fetching), so the `client` parameter is available up the call chain. - -**packages/utils/src/transaction.ts** (1 check): -- `SmartTransaction.completeFee()` at line 63 -- replace the inline DAO check block (lines 82-95) with `await assertDaoOutputLimit(this, client);` where `client` is available as `from.client` (the Signer's client property, matching how it's done in the CCC completeFee safety net). - -Note: SmartTransaction's `completeFee` is already async and already has access to client via the Signer parameter. Just replace the inline check. - -**CRITICAL: Update all callers of the methods whose signatures changed.** - -After adding `client` parameter to methods, search for all call sites: -- `this.daoManager.deposit(tx, ...)` in `packages/core/src/logic.ts` -- add `client` and `await` -- `this.daoManager.requestWithdrawal(tx, ...)` in `packages/core/src/owned_owner.ts` -- already passes client, but now needs `await` -- `this.daoManager.withdraw(tx, ...)` in `packages/core/src/owned_owner.ts` -- already passes client, but now needs `await` -- Any other call sites in SDK or apps -- search for `.deposit(`, `.requestWithdrawal(`, `.withdraw(` across the entire `packages/` directory - -For every caller that invokes a now-async method, add `await`. If the caller itself is not async, make it async too (cascade). - -Remove the old inline checks entirely (the 3-line blocks with the error string "More than 64 output cells in a NervosDAO transaction"). - - -1. `grep -r "outputs.length > 64" packages/` returns NO results (all inline checks removed) -2. `grep -r "assertDaoOutputLimit" packages/dao/src/dao.ts packages/core/src/logic.ts packages/core/src/owned_owner.ts packages/utils/src/transaction.ts` shows the utility is called in all 4 files -3. `pnpm check:full` passes -- no type errors from async/await cascading or missing client parameters - - -All 7 inline DAO output checks are removed. Every location now calls `await assertDaoOutputLimit(tx, client)`. All affected methods are async with the client parameter. All callers updated to await the now-async methods. `pnpm check:full` passes. - - - - - - -1. `grep -rn "outputs.length > 64" packages/` -- should return 0 results -2. `grep -rn "assertDaoOutputLimit" packages/ forks/ccc/packages/core/src/ckb/` -- should show usage in 4 iCKB files + definition in CCC -3. `grep -rn "ErrorNervosDaoOutputLimit" forks/ccc/packages/core/src/ckb/` -- should show class definition + export -4. `bash forks/forker/status.sh ccc` -- should exit 0 -5. `pnpm check:full` -- should pass clean - - - -- ErrorNervosDaoOutputLimit error class exists in CCC core with count/limit metadata -- assertDaoOutputLimit utility exists in CCC core using full Script.eq() comparison -- completeFee has DAO safety net -- All 7 scattered inline checks replaced with centralized utility calls -- No intermediate broken build state -- forks/ccc pins recorded - - - -After completion, create `.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md` - diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md deleted file mode 100644 index 96c6573..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 01 -subsystem: transaction -tags: [nervos-dao, error-handling, ccc-core, assertDaoOutputLimit, async-refactor] - -# Dependency graph -requires: [] -provides: - - ErrorNervosDaoOutputLimit error class in CCC core - - assertDaoOutputLimit centralized utility function in CCC core - - completeFee safety net for DAO output limit in CCC core - - forks/ccc local patch mechanism for deterministic builds -affects: [01-02, 01-03, 01-04] - -# Tech tracking -tech-stack: - added: [] - patterns: [centralized-dao-limit-check, forks/ccc-local-patches] - -key-files: - created: - - forks/.pin/ccc/local-001-dao-output-limit.patch (now part of .pin/ multi-file format) - modified: - - forks/ccc/packages/core/src/ckb/transactionErrors.ts - - forks/ccc/packages/core/src/ckb/transaction.ts - - forks/forker/record.sh - - forks/forker/replay.sh - - packages/dao/src/dao.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts - - packages/utils/src/transaction.ts - -key-decisions: - - "Added forks/ccc local patch mechanism (.pin/ccc/local-*.patch) to support deterministic replay of CCC source modifications" - - "Moved client parameter before optional options in DaoManager.requestWithdrawal and DaoManager.withdraw signatures" - - "assertDaoOutputLimit uses early return when outputs <= 64 for zero-cost in common case" - -patterns-established: - - "Local CCC patches: .pin/ccc/local-*.patch files applied after standard merge+patch cycle" - - "DAO output limit: always use ccc.assertDaoOutputLimit(tx, client) instead of inline checks" - -requirements-completed: [SMTX-06] - -# Metrics -duration: 30min -completed: 2026-02-22 ---- - -# Phase 01 Plan 01: DAO Output Limit Check Summary - -**Centralized NervosDAO 64-output limit into CCC core assertDaoOutputLimit utility, replacing all 7 scattered inline checks across dao/core/utils packages** - -## Performance - -- **Duration:** ~30 min -- **Started:** 2026-02-22T16:00:00Z -- **Completed:** 2026-02-22T16:30:00Z -- **Tasks:** 2 -- **Files modified:** 9 - -## Accomplishments -- Built ErrorNervosDaoOutputLimit error class with count/limit metadata in CCC core -- Built assertDaoOutputLimit utility function that checks both inputs and outputs for DAO type script using full Script.eq() comparison -- Added completeFee safety net in CCC Transaction class (both return paths) -- Replaced all 7 inline DAO output checks across 4 files with centralized utility calls -- Added local patch mechanism to forks/ccc record/replay for deterministic builds of CCC modifications - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Build ErrorNervosDaoOutputLimit and assertDaoOutputLimit in CCC core** - `7081869` (feat) -2. **Task 2: Replace all 7 scattered DAO checks with assertDaoOutputLimit calls** - `2decd06` (refactor) - -## Files Created/Modified -- `forks/ccc/packages/core/src/ckb/transactionErrors.ts` - ErrorNervosDaoOutputLimit error class -- `forks/ccc/packages/core/src/ckb/transaction.ts` - assertDaoOutputLimit utility + completeFee safety net -- `forks/.pin/ccc/` - Updated pins for deterministic replay -- `forks/forker/record.sh` - Added local patch preservation and application -- `forks/forker/replay.sh` - Added local patch application after standard merge+patch -- `packages/dao/src/dao.ts` - DaoManager.deposit/requestWithdrawal/withdraw now async with client param -- `packages/core/src/logic.ts` - LogicManager.deposit now async with client param -- `packages/core/src/owned_owner.ts` - OwnedOwnerManager.requestWithdrawal/withdraw now async with client param -- `packages/utils/src/transaction.ts` - SmartTransaction.completeFee DAO check replaced - -## Decisions Made -- Added forks/ccc local patch mechanism (.pin/ccc/local-*.patch) because the existing record/replay infrastructure had no way to persist source-level CCC modifications through the clean/replay cycle. This was a necessary blocking-issue fix (Rule 3). -- Placed `client: ccc.Client` parameter before optional `options` parameters in DaoManager signatures for cleaner API design (required params before optional). -- assertDaoOutputLimit uses early return when `outputs.length <= 64` so the common-case path has zero async overhead. - -## Deviations from Plan - -### Auto-fixed Issues - -**1. [Rule 3 - Blocking] Added forks/ccc local patch mechanism** -- **Found during:** Task 1 (CCC core changes) -- **Issue:** forks/ccc record/replay infrastructure had no way to persist local CCC source modifications. Running `bash forks/forker/record.sh ccc` or `pnpm check:full` would wipe changes because replay clones fresh from upstream. -- **Fix:** Added `.pin//local-*.patch` mechanism. Modified `record.sh` to preserve local patches during re-recording and apply them after standard merge+patch. Modified `replay.sh` to apply local patches after standard replay. Both use deterministic git identity/timestamps for reproducible HEAD SHAs. -- **Files modified:** `forks/forker/record.sh`, `forks/forker/replay.sh`, `forks/.pin/ccc/local-001-dao-output-limit.patch` -- **Verification:** `pnpm check:full` passes (clean wipe + replay + build cycle) -- **Committed in:** 7081869 (Task 1 commit) - ---- - -**Total deviations:** 1 auto-fixed (1 blocking) -**Impact on plan:** Essential infrastructure addition to make CCC modifications work through the deterministic build cycle. No scope creep. - -## Issues Encountered -- Plan incorrectly stated that `requestWithdrawal` and `withdraw` in DaoManager already had `client` as a parameter. They did not. Added `client` parameter to both methods and updated all callers. - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- assertDaoOutputLimit is available in CCC core for all packages -- DAO output limit check is centralized, ready for SmartTransaction removal in subsequent plans -- Local patch mechanism established for further CCC modifications if needed - -## Self-Check: PASSED - -- FOUND: forks/.pin/ccc/ (local patch integrated into multi-file format) -- FOUND: 01-01-SUMMARY.md -- FOUND: commit 7081869 (Task 1) -- FOUND: commit 2decd06 (Task 2) - ---- -*Phase: 01-ickb-utils-smarttransaction-removal* -*Completed: 2026-02-22* diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-PLAN.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-PLAN.md deleted file mode 100644 index 6813a56..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-PLAN.md +++ /dev/null @@ -1,272 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 02 -type: execute -wave: 2 -depends_on: - - "01-01" -files_modified: - - packages/utils/src/utils.ts - - packages/dao/src/cells.ts - - packages/dao/src/dao.ts - - packages/core/src/cells.ts - - packages/core/src/udt.ts - - packages/core/src/logic.ts - - packages/sdk/src/sdk.ts -autonomous: true -requirements: - - SMTX-04 - -must_haves: - truths: - - "The standalone `getHeader()` function and `HeaderKey` type no longer exist in `@ickb/utils`" - - "All 5 standalone `getHeader()` call sites inline CCC client calls (`client.getTransactionWithHeader()` or `client.getHeaderByNumber()`) with null checks" - - "All 2 `tx.getHeader()` instance method call sites in `core/src/udt.ts` inline CCC client calls" - - "All 3 `tx.addHeaders()` call sites push to `tx.headerDeps` directly with dedup logic" - - "The `TransactionHeader` type is preserved in a surviving file for DaoCell and ReceiptCell to import" - - "`pnpm check:full` passes after getHeader removal" - artifacts: - - path: "packages/utils/src/utils.ts" - provides: "Utility functions WITHOUT getHeader/HeaderKey; WITH TransactionHeader type" - contains: "TransactionHeader" - - path: "packages/dao/src/cells.ts" - provides: "DaoCell construction with inlined CCC client calls for header fetching" - contains: "client.getHeaderByNumber" - - path: "packages/core/src/cells.ts" - provides: "ReceiptCell construction with inlined CCC client calls" - contains: "client.getTransactionWithHeader" - key_links: - - from: "packages/dao/src/cells.ts" - to: "CCC Client API" - via: "client.getTransactionWithHeader and client.getHeaderByNumber" - pattern: "client\\.get(TransactionWithHeader|HeaderByNumber)" - - from: "packages/core/src/udt.ts" - to: "CCC Client API" - via: "client.getTransactionWithHeader for header resolution" - pattern: "client\\.getTransactionWithHeader" - - from: "packages/dao/src/dao.ts" - to: "tx.headerDeps" - via: "direct push with dedup replacing addHeaders" - pattern: "headerDeps\\.push" ---- - - -Remove the `getHeader()` function and `HeaderKey` type from `@ickb/utils`, inline CCC client calls at all 9+ call sites, replace `addHeaders()` with direct `tx.headerDeps` push, and preserve the `TransactionHeader` type for downstream consumers. - -Purpose: Eliminate SmartTransaction's header management infrastructure. CCC's built-in `ClientCacheMemory` LRU handles header caching transparently. This is Step 3 of the feature-slice execution order. - -Output: `getHeader`/`HeaderKey` deleted from utils.ts; all call sites use CCC client directly; `TransactionHeader` type moved to utils.ts; `addHeaders` replaced with headerDeps push. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md - -Key source files to read: -@packages/utils/src/utils.ts (getHeader function and HeaderKey type to remove) -@packages/utils/src/transaction.ts (TransactionHeader type at line 506-517 to move; addHeaders instance method; getHeader instance method) -@packages/dao/src/cells.ts (3 standalone getHeader call sites at lines 91, 97, 109) -@packages/dao/src/dao.ts (2 addHeaders call sites at lines 160, 216) -@packages/core/src/cells.ts (1 standalone getHeader call site at line 84) -@packages/core/src/udt.ts (2 tx.getHeader instance method call sites at lines 108, 125) -@packages/core/src/logic.ts (1 addHeaders call site at line 125) -@packages/sdk/src/sdk.ts (1 standalone getHeader call site at line 388) - - - - - - Task 1: Move TransactionHeader type and inline all getHeader/addHeaders call sites - - packages/utils/src/utils.ts - packages/utils/src/transaction.ts - packages/dao/src/cells.ts - packages/dao/src/dao.ts - packages/core/src/cells.ts - packages/core/src/udt.ts - packages/core/src/logic.ts - packages/sdk/src/sdk.ts - - -**Step 1: Move TransactionHeader type to utils.ts** - -Read `packages/utils/src/transaction.ts`. Find the `TransactionHeader` interface (around line 506-517). It looks approximately like: -```typescript -interface TransactionHeader { - header: ccc.ClientBlockHeader; - txHash?: ccc.Hex; -} -``` - -Read `packages/utils/src/utils.ts`. Add the `TransactionHeader` interface definition there (export it). This type is needed by `@ickb/dao` (DaoCell.headers) and `@ickb/core` (ReceiptCell.header). - -Also ensure `TransactionHeader` is exported from `packages/utils/src/index.ts` (it may already be re-exported from `transaction.ts` -- it will need to come from `utils.ts` after transaction.ts is deleted in Plan 03). - -**Step 2: Inline standalone getHeader() call sites (5 sites)** - -For each call site, replace `getHeader(client, { type, value })` with direct CCC client calls. Always include null check + throw. - -**packages/dao/src/cells.ts line 91** (number lookup): -```typescript -// Before: -const header = await getHeader(client, { type: "number", value: mol.Uint64LE.decode(cell.outputData) }); -// After: -const header = await client.getHeaderByNumber(mol.Uint64LE.decode(cell.outputData)); -if (!header) { - throw new Error("Header not found for block number"); -} -``` - -**packages/dao/src/cells.ts line 97** (txHash lookup): -```typescript -// Before: -const header = await getHeader(client, { type: "txHash", value: txHash }); -// After: -const txWithHeader = await client.getTransactionWithHeader(txHash); -if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); -} -const header = txWithHeader.header; -``` - -**packages/dao/src/cells.ts line 109** (txHash lookup): -Same pattern as line 97. - -**packages/core/src/cells.ts line 84** (txHash lookup): -Same pattern as above. Read the actual code to see the exact variable names and context. - -**packages/sdk/src/sdk.ts line 388** (txHash lookup): -Same pattern. Read the actual code to determine what `txHash` variable is used (likely `c.cell.outPoint.txHash`). - -Remove the `import { getHeader }` from each file after all call sites are updated. - -**Step 3: Inline tx.getHeader() instance method call sites (2 sites in core/src/udt.ts)** - -Read `packages/core/src/udt.ts`. At lines 108 and 125, `tx.getHeader()` is called (SmartTransaction instance method). Replace with CCC client calls: - -```typescript -// Before: -const header = await tx.getHeader(client, { type: "txHash", value: outPoint.txHash }); -// After: -const txWithHeader = await client.getTransactionWithHeader(outPoint.txHash); -if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); -} -const header = txWithHeader.header; -``` - -These methods already have `client` as a parameter, so no signature change is needed. - -**Step 4: Replace addHeaders() call sites (3 sites) with direct headerDeps push** - -Read each file. Replace `tx.addHeaders(...)` with direct push to `tx.headerDeps` with dedup. - -**packages/dao/src/dao.ts line 160** (single TransactionHeader): -```typescript -// Before: -tx.addHeaders(depositHeader); -// After: -const hash = depositHeader.header.hash; -if (!tx.headerDeps.some((h) => h === hash)) { - tx.headerDeps.push(hash); -} -``` - -**packages/dao/src/dao.ts line 216** (array of headers from DaoCell): -```typescript -// Before: -tx.addHeaders(...withdrawalRequests.flatMap(d => d.headers)); -// OR similar pattern -// After: -for (const wr of withdrawalRequests) { - for (const th of wr.headers) { - const hash = th.header.hash; - if (!tx.headerDeps.some((h) => h === hash)) { - tx.headerDeps.push(hash); - } - } -} -``` -Read the actual code carefully to determine the exact structure of the addHeaders call. - -**packages/core/src/logic.ts line 125** (receipt headers): -```typescript -// Before: -tx.addHeaders(...receipts.map(r => r.header)); -// OR similar -// After: -for (const r of receipts) { - const hash = r.header.header.hash; - if (!tx.headerDeps.some((h) => h === hash)) { - tx.headerDeps.push(hash); - } -} -``` -Read the actual code to see the exact shape. - -**Step 5: Remove getHeader function and HeaderKey type from utils.ts** - -Read `packages/utils/src/utils.ts`. Find and delete the `getHeader` function definition and the `HeaderKey` type definition. Remove any imports that were only used by `getHeader`. - -Also update `packages/utils/src/index.ts` to remove any re-export of `getHeader` or `HeaderKey` if they are exported there. - -**Step 6: Update imports across all modified files** - -- Remove `getHeader` and `HeaderKey` imports from all consumer files -- Add `TransactionHeader` import from `@ickb/utils` (the new location) in files that previously imported it from `transaction.ts` or `@ickb/utils` (it should already resolve correctly if the barrel export is set up) -- Ensure no circular imports are created - -**IMPORTANT NOTES:** -- Do NOT delete `transaction.ts` in this plan -- that happens in Plan 03 -- Do NOT change method signatures from SmartTransaction to TransactionLike -- that happens in Plan 03 -- The `addHeaders` and `getHeader` instance methods on SmartTransaction class itself will be cleaned up when the class is deleted in Plan 03 -- Preserve exact error semantics: the original `getHeader` threw on null results; the inlined code must also throw - - -1. `grep -rn "getHeader" packages/utils/src/utils.ts` -- should NOT find the function definition or HeaderKey type -2. `grep -rn "from.*getHeader\|getHeader(" packages/dao/ packages/core/ packages/sdk/` -- should NOT find standalone getHeader calls (instance method calls on SmartTransaction may still exist in transaction.ts itself, which is fine -- deleted in Plan 03) -3. `grep -rn "addHeaders" packages/dao/ packages/core/` -- should NOT find any addHeaders calls -4. `grep -rn "headerDeps.push" packages/dao/ packages/core/` -- should find the new direct push calls -5. `grep -rn "TransactionHeader" packages/utils/src/utils.ts` -- should find the type definition -6. `pnpm check:full` passes - - -`getHeader()` function and `HeaderKey` type are deleted from `@ickb/utils`. All 5 standalone `getHeader()` call sites use direct CCC client calls with null checks. All 2 `tx.getHeader()` instance method call sites in core/udt.ts use CCC client calls. All 3 `addHeaders()` call sites push to `tx.headerDeps` directly with dedup. `TransactionHeader` type is preserved in utils.ts and exported. `pnpm check:full` passes. - - - - - - -1. `grep -rn "getHeader\b" packages/utils/src/utils.ts` -- no function definition -2. `grep -rn "HeaderKey" packages/` -- no results (type fully removed) -3. `grep -rn "addHeaders" packages/dao/ packages/core/` -- no results -4. `grep -rn "client\.getTransactionWithHeader\|client\.getHeaderByNumber" packages/dao/ packages/core/ packages/sdk/` -- shows inlined calls -5. `grep -rn "headerDeps\.push" packages/dao/ packages/core/` -- shows direct push with dedup -6. `grep -rn "TransactionHeader" packages/utils/src/utils.ts` -- type preserved -7. `pnpm check:full` -- passes clean - - - -- getHeader() function deleted from @ickb/utils -- HeaderKey type deleted from @ickb/utils -- TransactionHeader type preserved and accessible from @ickb/utils -- All standalone getHeader call sites inline CCC client calls with proper null checks -- All tx.getHeader instance method call sites in core/udt.ts inline CCC client calls -- All addHeaders call sites push to tx.headerDeps with dedup -- CCC ClientCacheMemory handles header caching (no custom cache) -- Build stays green - - - -After completion, create `.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-SUMMARY.md` - diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-SUMMARY.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-SUMMARY.md deleted file mode 100644 index 04f5e3b..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-SUMMARY.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 02 -subsystem: transaction -tags: [getHeader, HeaderKey, addHeaders, CCC-client, header-management, inline-refactor] - -# Dependency graph -requires: - - phase: 01-01 - provides: assertDaoOutputLimit centralized in CCC core; DaoManager/LogicManager async signatures with client parameter -provides: - - TransactionHeader type in utils.ts (moved from transaction.ts) - - All consumer packages use direct CCC client calls for header fetching - - All consumer packages use direct tx.headerDeps push with dedup for header deps - - getHeader/HeaderKey removed from @ickb/utils public API -affects: [01-03] - -# Tech tracking -tech-stack: - added: [] - patterns: [inline-ccc-client-calls, direct-headerDeps-push-with-dedup] - -key-files: - created: [] - modified: - - packages/utils/src/utils.ts - - packages/utils/src/transaction.ts - - packages/dao/src/cells.ts - - packages/dao/src/dao.ts - - packages/core/src/cells.ts - - packages/core/src/udt.ts - - packages/core/src/logic.ts - - packages/sdk/src/sdk.ts - -key-decisions: - - "Moved getHeader/HeaderKey to transaction.ts as non-exported internals (deleted alongside SmartTransaction in 01-03)" - - "TransactionHeader moved to utils.ts as canonical location, imported by transaction.ts" - - "Inlined CCC client calls use explicit null checks with descriptive error messages matching original getHeader throw semantics" - -patterns-established: - - "Header fetching: use client.getTransactionWithHeader() or client.getHeaderByNumber() directly with null check + throw" - - "Header deps: push hash to tx.headerDeps with dedup via .some() check, no SmartTransaction wrapper" - -requirements-completed: [SMTX-04] - -# Metrics -duration: 6min -completed: 2026-02-22 ---- - -# Phase 01 Plan 02: getHeader/addHeaders Removal Summary - -**Removed getHeader()/HeaderKey from @ickb/utils public API, inlined 10 call sites with direct CCC client calls, replaced addHeaders with headerDeps push** - -## Performance - -- **Duration:** 6 min -- **Started:** 2026-02-22T16:23:02Z -- **Completed:** 2026-02-22T16:29:31Z -- **Tasks:** 1 -- **Files modified:** 8 - -## Accomplishments -- Removed getHeader() function and HeaderKey type from @ickb/utils public API -- Inlined 5 standalone getHeader() call sites in dao/cells.ts, core/cells.ts, and sdk/sdk.ts with direct CCC client calls (getTransactionWithHeader/getHeaderByNumber) with null checks -- Inlined 2 tx.getHeader() instance method call sites in core/udt.ts with direct CCC client calls -- Replaced 3 addHeaders() call sites in dao/dao.ts and core/logic.ts with direct tx.headerDeps push with dedup logic -- Moved TransactionHeader interface from transaction.ts to utils.ts as canonical export location - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Move TransactionHeader type and inline all getHeader/addHeaders call sites** - `85ead3a` (refactor) - -## Files Created/Modified -- `packages/utils/src/utils.ts` - Added TransactionHeader interface; removed getHeader function and HeaderKey type -- `packages/utils/src/transaction.ts` - Moved getHeader/HeaderKey to non-exported internals; imports TransactionHeader from utils.ts -- `packages/dao/src/cells.ts` - Inlined 3 getHeader calls with client.getHeaderByNumber and client.getTransactionWithHeader -- `packages/dao/src/dao.ts` - Replaced 2 addHeaders calls with direct tx.headerDeps push with dedup -- `packages/core/src/cells.ts` - Inlined 1 getHeader call with client.getTransactionWithHeader -- `packages/core/src/udt.ts` - Inlined 2 tx.getHeader calls with client.getTransactionWithHeader -- `packages/core/src/logic.ts` - Replaced 1 addHeaders call with direct tx.headerDeps push with dedup -- `packages/sdk/src/sdk.ts` - Inlined 1 getHeader call with client.getTransactionWithHeader - -## Decisions Made -- Moved getHeader/HeaderKey into transaction.ts as non-exported internals rather than deleting entirely. SmartTransaction's own instance methods (getHeader, encodeHeaderKey, addHeaders) still reference these internally. Deleting them would break SmartTransaction, which was removed in Plan 01-03. This kept the public API clean while maintaining internal consistency. -- TransactionHeader placed in utils.ts as the canonical location since it outlives SmartTransaction (used by DaoCell.headers and ReceiptCell.header). -- Inlined CCC client calls preserve the original error semantics: getHeader always threw on null results, and the inlined code also throws with descriptive messages. - -## Deviations from Plan - -### Auto-fixed Issues - -**1. [Rule 3 - Blocking] Retained getHeader/HeaderKey as non-exported internals in transaction.ts** -- **Found during:** Task 1 (Step 5 - removing getHeader from utils.ts) -- **Issue:** SmartTransaction class in transaction.ts imports and uses the standalone getHeader function and HeaderKey type internally. Removing them from utils.ts without providing them in transaction.ts would break the class. -- **Fix:** Moved getHeader function and HeaderKey type into transaction.ts as non-exported (internal) declarations. They are no longer part of the @ickb/utils public API but remained available for SmartTransaction's internal use until 01-03 deleted the class. -- **Files modified:** packages/utils/src/transaction.ts -- **Verification:** pnpm check:full passes; HeaderKey/getHeader not found in any consumer packages -- **Committed in:** 85ead3a (Task 1 commit) - ---- - -**Total deviations:** 1 auto-fixed (1 blocking) -**Impact on plan:** Necessary to keep SmartTransaction functional until 01-03 removed it. No scope creep. - -## Issues Encountered -None - plan executed smoothly once the internal SmartTransaction dependency was handled. - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- All getHeader/HeaderKey usage removed from public API and consumer packages -- TransactionHeader type available in utils.ts for downstream use -- SmartTransaction class ready for deletion in Plan 03 (all external dependencies on its header methods removed) -- Build stays green - -## Self-Check: PASSED - -- FOUND: all 8 modified files exist -- FOUND: 01-02-SUMMARY.md -- FOUND: commit 85ead3a (Task 1) - ---- -*Phase: 01-ickb-utils-smarttransaction-removal* -*Completed: 2026-02-22* diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-PLAN.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-PLAN.md deleted file mode 100644 index e10b792..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-PLAN.md +++ /dev/null @@ -1,328 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 03 -type: execute -wave: 3 -depends_on: - - "01-02" -files_modified: - - packages/utils/src/transaction.ts - - packages/utils/src/capacity.ts - - packages/utils/src/udt.ts - - packages/utils/src/index.ts - - packages/dao/src/dao.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts - - packages/core/src/udt.ts - - packages/order/src/order.ts - - packages/sdk/src/sdk.ts - - packages/sdk/src/constants.ts -autonomous: true -requirements: - - SMTX-01 - - SMTX-02 - -must_haves: - truths: - - "SmartTransaction class no longer exists in `@ickb/utils` source or exports" - - "CapacityManager class no longer exists in `@ickb/utils` source or exports" - - "All manager method signatures across ALL 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`" - - "All updated methods return `ccc.Transaction` (not void) following CCC convention" - - "Each method converts TransactionLike to Transaction internally with `ccc.Transaction.from(txLike)`" - - "UdtHandler interface and UdtManager class remain with updated signatures" - - "All `addUdtHandlers()` calls are replaced with `tx.addCellDeps(this.udtHandler.cellDeps)`" - - "`transaction.ts` and `capacity.ts` files are deleted from @ickb/utils" - - "`pnpm check:full` passes after full removal" - artifacts: - - path: "packages/utils/src/udt.ts" - provides: "UdtHandler interface and UdtManager class with TransactionLike signatures" - contains: "TransactionLike" - - path: "packages/utils/src/index.ts" - provides: "Barrel exports WITHOUT transaction.ts or capacity.ts" - key_links: - - from: "packages/dao/src/dao.ts" - to: "ccc.Transaction.from()" - via: "TransactionLike input conversion at method entry" - pattern: "Transaction\\.from\\(txLike\\)" - - from: "packages/order/src/order.ts" - to: "ccc.Transaction.from()" - via: "TransactionLike input conversion at method entry" - pattern: "Transaction\\.from\\(txLike\\)" - - from: "packages/sdk/src/sdk.ts" - to: "CCC client.findCellsOnChain" - via: "CapacityManager replacement" - pattern: "findCellsOnChain" ---- - - -Delete SmartTransaction class and CapacityManager class from `@ickb/utils`; update all manager method signatures across all 5 library packages from `SmartTransaction` to `ccc.TransactionLike`; replace `addUdtHandlers()` calls; update SDK to use CCC native cell finding. - -Purpose: Complete the SmartTransaction removal by deleting the class and its infrastructure after all dependencies have been resolved (DAO checks consolidated in Plan 01, header management inlined in Plan 02). This is Steps 4-5 of the feature-slice execution order. - -Output: `transaction.ts` and `capacity.ts` deleted; all method signatures accept `ccc.TransactionLike` and return `ccc.Transaction`; SDK uses CCC native cell finding; barrel exports cleaned. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-01-SUMMARY.md -@.planning/phases/01-ickb-utils-smarttransaction-removal/01-02-SUMMARY.md - -Key source files to read: -@packages/utils/src/transaction.ts (SmartTransaction class -- TO DELETE) -@packages/utils/src/capacity.ts (CapacityManager class -- TO DELETE) -@packages/utils/src/udt.ts (UdtHandler/UdtManager -- update signatures, keep) -@packages/utils/src/index.ts (barrel exports -- remove transaction.ts and capacity.ts) -@packages/dao/src/dao.ts (DaoManager methods -- update signatures) -@packages/core/src/logic.ts (LogicManager methods -- update signatures) -@packages/core/src/owned_owner.ts (OwnedOwnerManager methods -- update signatures) -@packages/core/src/udt.ts (IckbUdtManager -- update signatures) -@packages/order/src/order.ts (OrderManager methods -- update signatures) -@packages/sdk/src/sdk.ts (IckbSdk methods -- update signatures, replace CapacityManager) -@packages/sdk/src/constants.ts (getConfig -- remove CapacityManager) - - - - - - Task 1: Update all method signatures to TransactionLike and replace addUdtHandlers - - packages/utils/src/udt.ts - packages/dao/src/dao.ts - packages/core/src/logic.ts - packages/core/src/owned_owner.ts - packages/core/src/udt.ts - packages/order/src/order.ts - packages/sdk/src/sdk.ts - - -For every method across all 5 library packages that currently accepts `SmartTransaction`, apply the CCC convention: -1. Change parameter type from `SmartTransaction` (or `tx: SmartTransaction`) to `txLike: ccc.TransactionLike` -2. Add `const tx = ccc.Transaction.from(txLike);` as the FIRST line of the method body -3. Change return type from `void` to `ccc.Transaction` (for sync methods) or from `Promise` to `Promise` (for async methods, made async in Plan 01) -4. Add `return tx;` at the end of each method body -5. Replace `import { SmartTransaction }` with appropriate CCC imports (`ccc.TransactionLike`, `ccc.Transaction`) - -**packages/utils/src/udt.ts** -- UdtHandler interface + UdtManager class: -Read the file. Update ALL method signatures that accept `SmartTransaction`: -- `UdtHandler` interface methods (if any accept SmartTransaction) -- `UdtManager` methods: look for methods like `getInputsUdtBalance`, `getOutputsUdtBalance`, `addUdtChange`, etc. -- For `UdtManager` methods that mutate a transaction: accept `txLike: ccc.TransactionLike`, convert with `Transaction.from()`, return `ccc.Transaction` -- **Replace `addUdtHandlers` call in UdtManager** (line ~282): replace `tx.addUdtHandlers(this)` with `tx.addCellDeps(this.cellDeps)`. The handler registration was SmartTransaction-specific; only the cellDeps part survives. - -**packages/dao/src/dao.ts** -- DaoManager: -- `deposit(tx: SmartTransaction, ...)` -> `deposit(txLike: ccc.TransactionLike, ...): Promise` (already made async in Plan 01) -- `requestWithdrawal(tx: SmartTransaction, ...)` -> `requestWithdrawal(txLike: ccc.TransactionLike, ...): Promise` -- `withdraw(tx: SmartTransaction, ...)` -> `withdraw(txLike: ccc.TransactionLike, ...): Promise` -- Remove `SmartTransaction` import. Add `ccc.TransactionLike` and `ccc.Transaction` imports. - -**packages/core/src/logic.ts** -- LogicManager: -- `deposit(tx: SmartTransaction, ...)` -> `deposit(txLike: ccc.TransactionLike, ...): Promise` -- `completeDeposit(tx: SmartTransaction, ...)` -> `completeDeposit(txLike: ccc.TransactionLike, ...): ccc.Transaction` (or Promise if made async) -- Inner calls to `this.daoManager.deposit(tx, ...)` must pass `tx` (the converted Transaction, NOT txLike) and capture the return: `tx = await this.daoManager.deposit(tx, ...);` -- **Replace `addUdtHandlers` calls** (lines ~87, ~123): replace `tx.addUdtHandlers(this.udtHandler)` with `tx.addCellDeps(this.udtHandler.cellDeps)` - -**packages/core/src/owned_owner.ts** -- OwnedOwnerManager: -- `requestWithdrawal(tx: SmartTransaction, ...)` -> `requestWithdrawal(txLike: ccc.TransactionLike, ...): Promise` -- `withdraw(tx: SmartTransaction, ...)` -> `withdraw(txLike: ccc.TransactionLike, ...): Promise` -- Inner calls to `this.daoManager.*` must capture returned tx -- **Replace `addUdtHandlers` calls** (lines ~88, ~135): replace `tx.addUdtHandlers(this.udtHandler)` with `tx.addCellDeps(this.udtHandler.cellDeps)` - -**packages/core/src/udt.ts** -- IckbUdtManager: -- `getInputsUdtBalance(client, tx: SmartTransaction)` -> `getInputsUdtBalance(client, txLike: ccc.TransactionLike): Promise<...>` -- Any other methods accepting SmartTransaction -- Convert with `Transaction.from()` at entry - -**packages/order/src/order.ts** -- OrderManager: -- `mint(tx: SmartTransaction, ...)` -> `mint(txLike: ccc.TransactionLike, ...): ccc.Transaction` -- `addMatch(tx: SmartTransaction, ...)` -> `addMatch(txLike: ccc.TransactionLike, ...): ccc.Transaction` (or similar name) -- `melt(tx: SmartTransaction, ...)` -> `melt(txLike: ccc.TransactionLike, ...): ccc.Transaction` -- All other methods accepting SmartTransaction -- **Replace `addUdtHandlers` calls** (lines ~191, ~228, ~516): replace with `tx.addCellDeps(this.udtHandler.cellDeps)` - -**packages/sdk/src/sdk.ts** -- IckbSdk: -- `request(tx: SmartTransaction, ...)` -> `request(txLike: ccc.TransactionLike, ...): ccc.Transaction` -- `collect(tx: SmartTransaction, ...)` -> `collect(txLike: ccc.TransactionLike, ...): ccc.Transaction` -- Any other methods accepting SmartTransaction -- Inner calls to manager methods must capture returned tx - -**CRITICAL PATTERN for cascading returns:** - -When a method calls another method that now returns `ccc.Transaction`: -```typescript -// Before (void return, mutating tx in-place): -this.daoManager.deposit(tx, capacities, this.script); - -// After (Transaction return, must capture): -tx = await this.daoManager.deposit(tx, capacities, this.script, client); -``` - -The `Transaction.from()` at the callee entry point creates a new Transaction. The callee mutates and returns it. The caller must use the returned value for subsequent operations. - -**addUdtHandlers replacement analysis:** - -Per RESEARCH.md, all 8 `addUdtHandlers` call sites have a preceding `tx.addCellDeps(this.cellDeps)` call. The `addUdtHandlers` internally does: (1) register handler in `udtHandlers` Map (SmartTransaction-specific, lost), (2) call `addCellDeps(udtHandler.cellDeps)`. Replace each `tx.addUdtHandlers(this.udtHandler)` with `tx.addCellDeps(this.udtHandler.cellDeps)`. CCC's `addCellDeps` deduplicates, so this is safe even though `this.cellDeps` was just added on the preceding line. - - -1. `grep -rn "SmartTransaction" packages/dao/ packages/core/ packages/order/ packages/sdk/ packages/utils/src/udt.ts` -- should return NO results (no SmartTransaction type references) -2. `grep -rn "addUdtHandlers" packages/` -- should return NO results -3. `grep -rn "TransactionLike" packages/dao/ packages/core/ packages/order/ packages/sdk/ packages/utils/src/udt.ts` -- should show TransactionLike in method signatures -4. `grep -rn "Transaction\.from(txLike)" packages/` -- should show conversion at method entry points -5. `pnpm check:full` passes (SmartTransaction class still exists at this point, but nobody imports it) - - -All manager method signatures across all 5 library packages accept `ccc.TransactionLike` and return `ccc.Transaction`. Each method converts with `Transaction.from(txLike)` at entry. All 8 `addUdtHandlers()` calls replaced with `tx.addCellDeps(this.udtHandler.cellDeps)`. No file imports SmartTransaction. UdtHandler/UdtManager preserved with updated signatures. - - - - - Task 2: Delete SmartTransaction and CapacityManager, clean exports, update SDK - - packages/utils/src/transaction.ts - packages/utils/src/capacity.ts - packages/utils/src/index.ts - packages/sdk/src/sdk.ts - packages/sdk/src/constants.ts - - -**Step 1: Replace CapacityManager usage in SDK** - -Read `packages/sdk/src/sdk.ts`. Find the `findCapacities` usage (around line 376). The current pattern is: -```typescript -for await (const c of this.capacity.findCapacities(client, this.bots, opts)) { - // ... -} -``` - -Replace with CCC's native cell finding. Per RESEARCH.md: -```typescript -for (const lock of unique(this.bots)) { - for await (const cell of client.findCellsOnChain( - { - script: lock, - scriptType: "lock", - filter: { - scriptLenRange: [0n, 1n], - }, - scriptSearchMode: "exact", - withData: true, - }, - "asc", - 400, - )) { - if (cell.cellOutput.type !== undefined || !cell.cellOutput.lock.eq(lock)) { - continue; - } - // ... rest of existing logic - } -} -``` - -Read the existing code carefully to understand exactly what `findCapacities` does and replicate the filtering behavior. The key filter is: cells with no type script (plain CKB capacity cells), matching the lock script exactly. - -Also read `packages/sdk/src/constants.ts`. Find the `CapacityManager` usage (likely `CapacityManager.withAnyData()` in `getConfig`). Remove: -1. The `CapacityManager` import -2. The `CapacityManager.withAnyData()` call or instantiation -3. The `capacity` field from the return type (if it's part of a config object) - -Update `IckbSdk` constructor or `from()` factory to no longer accept/store a `CapacityManager` instance. Remove the `this.capacity` field. - -**Step 2: Delete transaction.ts** - -Delete the file: `packages/utils/src/transaction.ts` - -This file contains SmartTransaction class (~517 lines). After Plan 01 (DAO checks removed from completeFee) and Plan 02 (getHeader/addHeaders/TransactionHeader moved), and Task 1 of this plan (all consumers updated), nothing should import from this file. - -IMPORTANT: Verify that `TransactionHeader` was already moved to `utils.ts` in Plan 02. If not, ensure it's moved before deletion. - -**Step 3: Delete capacity.ts** - -Delete the file: `packages/utils/src/capacity.ts` - -This file contains CapacityManager class (~221 lines). After Step 1 replaced SDK usage, nothing should import from this file. - -**Step 4: Clean barrel exports in index.ts** - -Read `packages/utils/src/index.ts`. Remove: -- `export * from "./transaction.js";` (or similar barrel export for transaction.ts) -- `export * from "./capacity.js";` (or similar barrel export for capacity.ts) - -Keep: -- `export * from "./utils.js";` (has TransactionHeader now) -- `export * from "./udt.js";` (UdtHandler/UdtManager with updated signatures) -- `export * from "./codec.js";` -- `export * from "./heap.js";` - -**Step 5: Remove all SmartTransaction imports from remaining files** - -Search the entire `packages/` and `apps/` directories for any remaining `SmartTransaction` imports or references: -``` -grep -rn "SmartTransaction" packages/ apps/ -``` - -If any remain (e.g., in `apps/faucet/src/main.ts` which uses SmartTransaction), update those too: -- Replace `new SmartTransaction()` with `ccc.Transaction.default()` or `new ccc.Transaction()` -- Replace `SmartTransaction.from(...)` with `ccc.Transaction.from(...)` -- Update any `completeFeeChangeToLock` calls to use `ccc.Transaction.completeFeeChangeToLock()` -- Remove `SmartTransaction` imports - -**Step 6: Final build verification** - -Run `pnpm check:full` to verify the entire build is green. This validates: -- No broken imports (transaction.ts and capacity.ts deleted cleanly) -- No type errors from signature changes -- All packages compile under strict TypeScript settings - -**Clean delete rules from CONTEXT.md:** -- No deprecation stubs, no migration comments, no breadcrumbs -- File deletions + barrel export removal in the same commit (atomic) - - -1. `ls packages/utils/src/transaction.ts 2>/dev/null` -- file should NOT exist -2. `ls packages/utils/src/capacity.ts 2>/dev/null` -- file should NOT exist -3. `grep -rn "SmartTransaction" packages/ apps/` -- should return NO results -4. `grep -rn "CapacityManager" packages/ apps/` -- should return NO results -5. `grep -rn "transaction\.js\|capacity\.js" packages/utils/src/index.ts` -- should NOT find these exports -6. `grep -rn "findCellsOnChain" packages/sdk/src/sdk.ts` -- should show CCC native cell finding -7. `pnpm check:full` passes - - -`transaction.ts` and `capacity.ts` are deleted from `@ickb/utils`. Barrel exports cleaned. SmartTransaction class and CapacityManager class no longer exist anywhere. SDK uses CCC `client.findCellsOnChain()` for cell finding. No SmartTransaction or CapacityManager references remain in the codebase. `pnpm check:full` passes. - - - - - - -1. `ls packages/utils/src/transaction.ts packages/utils/src/capacity.ts 2>&1` -- both files gone -2. `grep -rn "SmartTransaction\|CapacityManager" packages/ apps/` -- zero results -3. `grep -rn "addUdtHandlers" packages/` -- zero results -4. `grep -rn "TransactionLike" packages/dao/ packages/core/ packages/order/ packages/sdk/ packages/utils/src/udt.ts` -- shows new signatures -5. `grep -rn "Transaction\.from(txLike)" packages/` -- shows CCC conversion pattern -6. `grep -rn "export.*from.*transaction\|export.*from.*capacity" packages/utils/src/index.ts` -- no exports from deleted files -7. `pnpm check:full` -- passes clean with all 5 library packages compiling - - - -- SmartTransaction class deleted from @ickb/utils (transaction.ts gone) -- CapacityManager class deleted from @ickb/utils (capacity.ts gone) -- All manager method signatures accept ccc.TransactionLike, return ccc.Transaction -- UdtHandler/UdtManager preserved with updated signatures (deferred to Phase 3+) -- All addUdtHandlers calls replaced with addCellDeps -- SDK uses CCC native cell finding instead of CapacityManager -- Barrel exports clean (no references to deleted files) -- No SmartTransaction or CapacityManager references anywhere in codebase -- pnpm check:full passes - - - -After completion, create `.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-SUMMARY.md` - diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-SUMMARY.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-SUMMARY.md deleted file mode 100644 index d47d32c..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-03-SUMMARY.md +++ /dev/null @@ -1,165 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -plan: 03 -subsystem: transaction -tags: [SmartTransaction, CapacityManager, TransactionLike, ccc-Transaction, API-cleanup] - -# Dependency graph -requires: - - phase: 01-01 - provides: assertDaoOutputLimit centralized in CCC core; DaoManager/LogicManager async signatures with client parameter - - phase: 01-02 - provides: getHeader/HeaderKey removed from public API; all consumer packages use direct CCC client calls; TransactionHeader moved to utils.ts -provides: - - All manager methods accept ccc.TransactionLike and return ccc.Transaction - - SmartTransaction class and CapacityManager class fully deleted from @ickb/utils - - addUdtHandlers replaced with tx.addCellDeps(udtHandler.cellDeps) across all packages - - defaultFindCellsLimit moved from capacity.ts to utils.ts -affects: [01-04] - -# Tech tracking -tech-stack: - added: [] - patterns: [TransactionLike-input-Transaction-return, direct-findCellsOnChain] - -key-files: - created: [] - modified: - - packages/utils/src/udt.ts - - packages/utils/src/utils.ts - - packages/utils/src/index.ts - - packages/dao/src/dao.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts - - packages/core/src/udt.ts - - packages/order/src/order.ts - - packages/sdk/src/sdk.ts - - packages/sdk/src/constants.ts - - apps/faucet/src/main.ts - deleted: - - packages/utils/src/transaction.ts - - packages/utils/src/capacity.ts - -key-decisions: - - "Methods accept ccc.TransactionLike and return ccc.Transaction with ccc.Transaction.from(txLike) at entry, enabling callers to pass plain objects or existing Transactions" - - "Replaced addUdtHandlers with tx.addCellDeps(this.udtHandler.cellDeps) since addUdtHandlers was just a wrapper around addCellDeps" - - "SDK getCkb() replaced CapacityManager.findCapacities with direct client.findCellsOnChain calls with scriptLenRange filter" - - "defaultFindCellsLimit moved from capacity.ts to utils.ts to preserve existing imports across packages" - -patterns-established: - - "TransactionLike pattern: all methods accept ccc.TransactionLike and return ccc.Transaction, converting with Transaction.from() at entry" - - "Cell deps: use tx.addCellDeps(handler.cellDeps) directly instead of wrapper methods" - -requirements-completed: [SMTX-01, SMTX-02, SMTX-03, SMTX-05] - -# Metrics -duration: 16min -completed: 2026-02-22 ---- - -# Phase 01 Plan 03: SmartTransaction/CapacityManager Deletion Summary - -**Deleted SmartTransaction class and CapacityManager class from @ickb/utils, replaced all 20+ method signatures with ccc.TransactionLike input / ccc.Transaction return pattern** - -## Performance - -- **Duration:** 16 min -- **Started:** 2026-02-22T16:31:36Z -- **Completed:** 2026-02-22T16:47:58Z -- **Tasks:** 2 -- **Files modified:** 13 (11 modified, 2 deleted) - -## Accomplishments -- Updated all manager method signatures across 7 files in 5 packages to accept ccc.TransactionLike and return ccc.Transaction -- Replaced all 8 addUdtHandlers() calls with direct tx.addCellDeps(this.udtHandler.cellDeps) -- Deleted SmartTransaction class (460+ lines) and CapacityManager class (220+ lines) from @ickb/utils -- Replaced CapacityManager usage in SDK with direct client.findCellsOnChain calls -- Updated faucet app to use ccc.Transaction.default() with inline cell queries -- Moved defaultFindCellsLimit constant to utils.ts, preserving all downstream imports - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Update method signatures from SmartTransaction to TransactionLike** - `2e832ae` (refactor) -2. **Task 2: Delete SmartTransaction/CapacityManager and clean exports** - `de8f4a7` (refactor) - -## Files Created/Modified -- `packages/utils/src/udt.ts` - UdtHandler interface and UdtManager class: TransactionLike signatures, addUdts returns Transaction -- `packages/utils/src/utils.ts` - Added defaultFindCellsLimit constant (moved from capacity.ts) -- `packages/utils/src/index.ts` - Removed capacity.js and transaction.js barrel exports -- `packages/dao/src/dao.ts` - DaoManager deposit/requestWithdrawal/withdraw: TransactionLike in, Transaction out -- `packages/core/src/logic.ts` - LogicManager deposit/completeDeposit: TransactionLike in, Transaction out -- `packages/core/src/owned_owner.ts` - OwnedOwnerManager requestWithdrawal/withdraw: TransactionLike in, Transaction out -- `packages/core/src/udt.ts` - IckbUdtManager getInputsUdtBalance: TransactionLike parameter -- `packages/order/src/order.ts` - OrderManager mint/addMatch/melt: TransactionLike in, Transaction out -- `packages/sdk/src/sdk.ts` - IckbSdk request/collect: TransactionLike in, Transaction out; getCkb uses findCellsOnChain -- `packages/sdk/src/constants.ts` - Removed CapacityManager from getConfig return type -- `apps/faucet/src/main.ts` - Uses ccc.Transaction.default() + inline findCellsOnChain -- `packages/utils/src/transaction.ts` - DELETED (SmartTransaction class) -- `packages/utils/src/capacity.ts` - DELETED (CapacityManager class) - -## Decisions Made -- Methods accept ccc.TransactionLike and return ccc.Transaction. This uses ccc.Transaction.from(txLike) at method entry, which is a no-op if the input is already a Transaction instance. Callers can pass plain transaction-like objects or existing Transactions interchangeably. -- Replaced addUdtHandlers with tx.addCellDeps(this.udtHandler.cellDeps) because addUdtHandlers was internally just a loop calling addCellDeps on each handler's cellDeps array. The direct call is more transparent. -- SDK getCkb() uses direct findCellsOnChain with scriptLenRange: [0n, 1n] filter (no type script) to replicate CapacityManager.withAnyData() behavior, plus explicit lock.eq() check for correctness. -- Deferred SDK CapacityManager removal from Task 1 to Task 2 to keep each task independently compilable. - -## Deviations from Plan - -### Auto-fixed Issues - -**1. [Rule 3 - Blocking] Deferred SDK constructor change from Task 1 to Task 2** -- **Found during:** Task 1 (signature updates) -- **Issue:** Removing CapacityManager from SDK constructor in Task 1 caused lint errors because getCkb() still referenced this.capacity. The plan specified removing SDK capacity in Task 2 but the constructor change in Task 1 broke the build. -- **Fix:** Kept CapacityManager import and constructor field in SDK during Task 1, then properly removed both in Task 2 alongside the findCellsOnChain replacement. -- **Files modified:** packages/sdk/src/sdk.ts -- **Verification:** pnpm check:full passes after both tasks -- **Committed in:** de8f4a7 (Task 2 commit) - -**2. [Rule 1 - Bug] Removed unused 'collect' import in faucet app** -- **Found during:** Task 2 (faucet update) -- **Issue:** After replacing CapacityManager with inline findCellsOnChain, the 'collect' import became unused, causing lint failure. -- **Fix:** Removed unused import. -- **Files modified:** apps/faucet/src/main.ts -- **Verification:** pnpm check:full passes -- **Committed in:** de8f4a7 (Task 2 commit) - ---- - -**Total deviations:** 2 auto-fixed (1 blocking, 1 bug) -**Impact on plan:** Necessary task-boundary adjustment to keep each task independently buildable. No scope creep. - -## Issues Encountered -- defaultFindCellsLimit was exported from both utils.ts and capacity.ts via barrel index.ts, causing TS2308 ambiguous export error. Resolved by keeping it in capacity.ts during Task 1 and moving to utils.ts only after capacity.ts deletion in Task 2. - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- SmartTransaction and CapacityManager fully removed from codebase -- All packages use standard CCC Transaction types -- @ickb/utils public API is clean: only exports codec, heap, udt, and utils modules -- Ready for Plan 04 (completeFee refactoring) which can now use plain ccc.Transaction - -## Self-Check: PASSED - -- FOUND: packages/utils/src/udt.ts -- FOUND: packages/utils/src/utils.ts -- FOUND: packages/utils/src/index.ts -- FOUND: packages/dao/src/dao.ts -- FOUND: packages/core/src/logic.ts -- FOUND: packages/core/src/owned_owner.ts -- FOUND: packages/core/src/udt.ts -- FOUND: packages/order/src/order.ts -- FOUND: packages/sdk/src/sdk.ts -- FOUND: packages/sdk/src/constants.ts -- FOUND: apps/faucet/src/main.ts -- MISSING (expected): packages/utils/src/transaction.ts (deleted) -- MISSING (expected): packages/utils/src/capacity.ts (deleted) -- FOUND: commit 2e832ae (Task 1) -- FOUND: commit de8f4a7 (Task 2) - ---- -*Phase: 01-ickb-utils-smarttransaction-removal* -*Completed: 2026-02-22* diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md deleted file mode 100644 index 98c0dcc..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md +++ /dev/null @@ -1,100 +0,0 @@ -# Phase 1: SmartTransaction Removal (feature-slice) - Context - -**Gathered:** 2026-02-22 -**Status:** Ready for planning - - -## Phase Boundary - -Delete SmartTransaction class and its infrastructure across all packages; contribute 64-output DAO limit check to CCC core; remove getHeader()/HeaderKey and inline CCC client calls; migrate all method signatures to ccc.TransactionLike. Using a **feature-slice approach**: each removal is chased across ALL packages so the build stays green at every step. - - - - -## Implementation Decisions - -### CCC DAO Contribution (via forks/ccc/) -- Build the 64-output NervosDAO limit check **in CCC core**, not in @ickb/utils -- Develop in `forks/ccc/`, record pins, use immediately via workspace override while waiting for upstream merge -- **Submit the upstream CCC PR during Phase 1 execution** -- CCC PR includes three components: - 1. **`completeFee()` safety net** — async check using `client.getKnownScript(KnownScript.NervosDao)` with full `Script.eq()` comparison - 2. **Standalone utility function** — `assertDaoOutputLimit(tx, client)` that auto-resolves unresolved inputs (populating `CellInput.cellOutput` as a side effect) and checks both inputs and outputs - 3. **`ErrorNervosDaoOutputLimit` error class** in `transactionErrors.ts` with metadata fields (count) and hardcoded limit of 64 -- The check logic: if `outputs.length > 64` AND any input or output has DAO type script, throw error -- **PR description should mention** the possibility of adding the check to `addOutput()` as a future enhancement, inviting maintainer feedback -- All 6+ scattered DAO checks across dao/core/utils packages are replaced with calls to the new CCC utility **in Phase 1** - -### getHeader() Removal -- **Remove `getHeader()` function and `HeaderKey` type entirely** from @ickb/utils -- Inline CCC client calls at each of the 8+ call sites across dao/core/sdk: - - `txHash` lookups → `(await client.getTransactionWithHeader(hash))?.header` with null check/throw - - `number` lookups → `await client.getHeaderByNumber(n)` with null check/throw -- SmartTransaction's redundant `Map` cache is deleted — CCC's built-in `ClientCacheMemory` LRU (128 blocks) handles caching -- **`addHeaders()` replacement needed** — `SmartTransaction.addHeaders()` is used by DaoManager (`requestWithdrawal`, `withdraw`) and LogicManager (`completeDeposit`) to push header hashes into `tx.headerDeps` with dedup. With SmartTransaction gone, these 3 call sites need to push to `tx.headerDeps` directly. Note: `SmartTransaction.getHeader()` (instance method) only validated that headers were already in headerDeps — it did not populate them. The standalone `getHeader()` function (being removed) never touched headerDeps at all. -- ROADMAP success criteria updated to reflect this — no standalone `getHeader()` utility will exist - -### Feature-Slice Build Strategy -- **Build must pass after every removal step** — no intermediate broken states -- Execution order: - 1. CCC DAO utility (adds new code, nothing breaks) - 2. Replace all scattered DAO checks with CCC utility calls (all packages) - 3. Remove `getHeader()`/`HeaderKey` and inline CCC calls at all call sites (all packages) - 4. Remove SmartTransaction class and update all method signatures to `ccc.TransactionLike` (all packages) - 5. Remove CapacityManager and update SDK call sites (utils + sdk) -- Each step touches multiple packages but leaves `pnpm check:full` passing -- **Roadmap updated**: Phases 4-5 reduced in scope since method signatures are already updated to `ccc.TransactionLike` in Phase 1 - -### Method Signatures (CCC Pattern) -- Follow CCC's convention: public APIs accept `ccc.TransactionLike` (flexible input), return `ccc.Transaction` (concrete) -- Convert internally with `ccc.Transaction.from(txLike)` at method entry point -- Consistent with how CCC's own udt/spore/type-id packages work - -### UdtHandler/UdtManager — Deferred -- UdtHandler interface and UdtManager class **stay in @ickb/utils** for Phase 1 -- Their method signatures are updated from `SmartTransaction` to `ccc.TransactionLike` to keep the build green -- Full replacement deferred to Phase 3+ (depends on CCC Udt integration investigation) -- `addUdtHandlers()` call sites — Claude's discretion on replacement approach - -### CapacityManager — Fully Removed -- CapacityManager is deleted from @ickb/utils -- Only consumer is `@ickb/sdk` (`findCapacities()` in sdk.ts, constructor in constants.ts) -- SDK call sites updated to use CCC's native cell finding - -### Removal Approach -- **Clean delete** — no deprecation stubs, no migration comments, no breadcrumbs -- File deletions + barrel export removal in the **same commit** (atomic) -- Files deleted: `transaction.ts`, `capacity.ts` (from @ickb/utils) -- Files kept: `udt.ts` (signatures updated), `utils.ts` (getHeader/HeaderKey removed), `codec.ts`, `heap.ts`, `index.ts` -- `utils.ts` keeps its name — no rename needed - -### Claude's Discretion -- `addUdtHandlers()` replacement strategy at call sites -- CapacityManager replacement approach in SDK (CCC native equivalent) -- Exact commit boundaries within each feature-slice step -- CCC PR code style and test approach (follow CCC's vitest patterns) - - - - -## Specific Ideas - -- **Script comparison must use `eq()`** — never compare just `codeHash`. Always compare the full Script (codeHash + hashType + args) using CCC's `Script.eq()` method. This applies across the entire codebase, not just the DAO check. Downstream agents must follow this pattern for all script identification. -- NervosDao type script is invariant across mainnet, testnet, devnet — the code hash is a genesis constant. The CCC PR can reference this fact. -- CCC's existing `Cell.isNervosDao(client)` is async and uses client resolution — the new utility should be consistent with this pattern. -- The CCC PR should follow CCC's error class conventions: see `ErrorTransactionInsufficientCapacity` and `ErrorTransactionInsufficientCoin` in `transactionErrors.ts` for the pattern. - - - - -## Deferred Ideas - -- **addOutput() DAO check** — Sync check in `Transaction.addOutput()` using hardcoded DAO script when outputs > 64. Deferred due to CCC maintainer acceptance concerns (hot path overhead, even though it only triggers past 64 outputs). Mentioned in CCC PR description as future possibility. -- **getHeader as CCC contribution** — A unified header lookup function (`client.getHeader(key)`) could be contributed to CCC itself, making iCKB's wrapper unnecessary. Low priority since the wrapper is being removed and calls inlined. - - - ---- - -*Phase: 01-ickb-utils-smarttransaction-removal* -*Context gathered: 2026-02-22* diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md deleted file mode 100644 index f4e5b64..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-RESEARCH.md +++ /dev/null @@ -1,567 +0,0 @@ -# Phase 1: SmartTransaction Removal (feature-slice) - Research - -**Researched:** 2026-02-22 -**Domain:** TypeScript refactoring / CCC blockchain SDK alignment -**Confidence:** HIGH - -## Summary - -Phase 1 removes `SmartTransaction`, `CapacityManager`, `getHeader()`/`HeaderKey`, and 7 scattered 64-output DAO limit checks. It contributes the DAO check to CCC core via `forks/ccc/`, updates all manager method signatures across all 5 library packages from `SmartTransaction` to `ccc.TransactionLike`, and keeps the build green after every step. - -The codebase is well-structured: SmartTransaction has exactly 9 consumer files across 5 packages; `getHeader` has 5 standalone call sites plus 4 instance method call sites; the 64-output DAO check appears in 7 locations across 4 files. CCC's native `Transaction` already handles DAO profit in `getInputsCapacity()` via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()`, making SmartTransaction's `getInputsCapacity` override redundant. CCC's `Transaction.from(txLike)` provides the `TransactionLike` -> `Transaction` entry-point conversion pattern that all updated method signatures will follow. - -**Primary recommendation:** Execute in the exact 5-step sequence from CONTEXT.md, with CCC DAO utility first (purely additive), then sweep each removal across all packages before moving to the next removal. Every step must pass `pnpm check:full`. - - -## User Constraints (from CONTEXT.md) - -### Locked Decisions -- Build the 64-output NervosDAO limit check **in CCC core**, not in @ickb/utils -- Develop in `forks/ccc/`, record pins, use immediately via workspace override while waiting for upstream merge -- **Submit the upstream CCC PR during Phase 1 execution** -- CCC PR includes three components: - 1. **`completeFee()` safety net** -- async check using `client.getKnownScript(KnownScript.NervosDao)` with full `Script.eq()` comparison - 2. **Standalone utility function** -- `assertDaoOutputLimit(tx, client)` that auto-resolves unresolved inputs (populating `CellInput.cellOutput` as a side effect) and checks both inputs and outputs - 3. **`ErrorNervosDaoOutputLimit` error class** in `transactionErrors.ts` with metadata fields (count) and hardcoded limit of 64 -- The check logic: if `outputs.length > 64` AND any input or output has DAO type script, throw error -- **PR description should mention** the possibility of adding the check to `addOutput()` as a future enhancement, inviting maintainer feedback -- All 6+ scattered DAO checks across dao/core/utils packages are replaced with calls to the new CCC utility **in Phase 1** -- **Remove `getHeader()` function and `HeaderKey` type entirely** from @ickb/utils -- Inline CCC client calls at each of the 8+ call sites across dao/core/sdk -- SmartTransaction's redundant `Map` cache is deleted -- CCC's built-in `ClientCacheMemory` LRU (128 blocks) handles caching -- **`addHeaders()` replacement needed** -- 3 call sites push to `tx.headerDeps` directly -- **Build must pass after every removal step** -- no intermediate broken states -- Execution order: - 1. CCC DAO utility (adds new code, nothing breaks) - 2. Replace all scattered DAO checks with CCC utility calls (all packages) - 3. Remove `getHeader()`/`HeaderKey` and inline CCC calls at all call sites (all packages) - 4. Remove SmartTransaction class and update all method signatures to `ccc.TransactionLike` (all packages) - 5. Remove CapacityManager and update SDK call sites (utils + sdk) -- Follow CCC's convention: public APIs accept `ccc.TransactionLike` (flexible input), return `ccc.Transaction` (concrete) -- Convert internally with `ccc.Transaction.from(txLike)` at method entry point -- UdtHandler interface and UdtManager class **stay in @ickb/utils** for Phase 1, signatures updated from `SmartTransaction` to `ccc.TransactionLike` -- CapacityManager is deleted from @ickb/utils; SDK call sites updated to use CCC's native cell finding -- **Clean delete** -- no deprecation stubs, no migration comments, no breadcrumbs -- File deletions + barrel export removal in the **same commit** (atomic) -- Files deleted: `transaction.ts`, `capacity.ts` (from @ickb/utils) -- Files kept: `udt.ts` (signatures updated), `utils.ts` (getHeader/HeaderKey removed), `codec.ts`, `heap.ts`, `index.ts` -- Script comparison must use full `Script.eq()` (codeHash + hashType + args), never just `codeHash` - -### Claude's Discretion -- `addUdtHandlers()` replacement strategy at call sites -- CapacityManager replacement approach in SDK (CCC native equivalent) -- Exact commit boundaries within each feature-slice step -- CCC PR code style and test approach (follow CCC's vitest patterns) - -### Deferred Ideas (OUT OF SCOPE) -- **addOutput() DAO check** -- Sync check in `Transaction.addOutput()`. Deferred due to CCC maintainer acceptance concerns. Mentioned in CCC PR description as future possibility. -- **getHeader as CCC contribution** -- A unified header lookup function. Low priority since the wrapper is being removed and calls inlined. - - - -## Phase Requirements - -| ID | Description | Research Support | -|----|-------------|-----------------| -| SMTX-01 | All manager method signatures across all 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction` | Exact inventory: 9 files use SmartTransaction type across 5 packages; CCC's `Transaction.from(txLike)` is the conversion pattern; all method signatures identified with line numbers | -| SMTX-02 | `SmartTransaction` class and its `completeFee()` override deleted from `@ickb/utils` | SmartTransaction in `transaction.ts` (480 lines); `completeFee()` override (lines 63-98) wraps UDT handlers + DAO check; CCC's native `getInputsCapacity` already handles DAO profit -- override is redundant | -| SMTX-04 | `getHeader()` function and `HeaderKey` type removed; all call sites inline CCC client calls | 5 standalone `getHeader` call sites + 4 `tx.getHeader` instance method call sites identified; each maps to `client.getTransactionWithHeader(hash)?.header` or `client.getHeaderByNumber(n)`; 3 `addHeaders` call sites need `tx.headerDeps.push()` with dedup | -| SMTX-06 | 64-output NervosDAO limit check consolidated into a single CCC utility | 7 check locations across 4 files identified; CCC error class pattern documented from `transactionErrors.ts`; `completeFee()` integration point identified; CCC vitest test patterns documented | - - -## Standard Stack - -### Core -| Library | Version | Purpose | Why Standard | -|---------|---------|---------|--------------| -| `@ckb-ccc/core` | catalog: (^1.12.2) | CKB blockchain SDK | Project's core dependency; `Transaction`, `TransactionLike`, `Client`, `Script.eq()` | -| TypeScript | ^5.9.3 (strict mode) | Type safety | `noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride` | -| tsgo | native-preview | Type checking | Used via `tsgo-filter.sh` (repo root) when CCC is cloned | -| vitest | ^3.2.4 | Testing | CCC's test framework; tests for the CCC PR | -| pnpm | 10.30.1 | Package management | Workspace protocol, catalog specifiers | - -### Supporting -| Library | Version | Purpose | When to Use | -|---------|---------|---------|-------------| -| `forks/ccc/` system | local | Local CCC development | Building/testing CCC DAO contribution before upstream merge | -| `@changesets/cli` | ^2.29.8 | Versioning | After API changes, run `pnpm changeset` | - -### Alternatives Considered -No alternatives -- this is a refactoring phase within an existing codebase. All decisions are locked. - -## Architecture Patterns - -### Recommended Project Structure -``` -packages/ -├── utils/src/ -│ ├── codec.ts # Molecule codec utilities (kept) -│ ├── heap.ts # MinHeap (kept) -│ ├── udt.ts # UdtHandler/UdtManager (kept, signatures updated) -│ ├── utils.ts # Utility functions (getHeader/HeaderKey REMOVED) -│ ├── index.ts # Barrel exports (transaction.ts + capacity.ts removed) -│ ├── transaction.ts # DELETED (SmartTransaction) -│ └── capacity.ts # DELETED (CapacityManager) -├── dao/src/ -│ ├── dao.ts # DaoManager (SmartTransaction -> TransactionLike) -│ └── cells.ts # DaoCell (getHeader inlined) -├── core/src/ -│ ├── logic.ts # LogicManager (SmartTransaction -> TransactionLike) -│ ├── owned_owner.ts # OwnedOwnerManager (SmartTransaction -> TransactionLike) -│ ├── udt.ts # IckbUdtManager (SmartTransaction -> TransactionLike) -│ └── cells.ts # ReceiptCell/etc (getHeader inlined) -├── order/src/ -│ └── order.ts # OrderManager (SmartTransaction -> TransactionLike) -├── sdk/src/ -│ ├── sdk.ts # IckbSdk (SmartTransaction -> TransactionLike, CapacityManager removed) -│ └── constants.ts # getConfig (CapacityManager removed) -forks/ccc/packages/core/src/ckb/ -├── transactionErrors.ts # + ErrorNervosDaoOutputLimit (new) -└── transaction.ts # + completeFee safety net + assertDaoOutputLimit (new) -``` - -### Pattern 1: TransactionLike Input / Transaction Output -**What:** CCC convention for public APIs that transform transactions -**When to use:** Every manager method that accepts a transaction -**Example:** -```typescript -// Source: CCC packages (udt, type-id, spore) all follow this pattern -// Before: -deposit(tx: SmartTransaction, capacities: ccc.FixedPoint[], lock: ccc.Script): void - -// After: -deposit(txLike: ccc.TransactionLike, capacities: ccc.FixedPoint[], lock: ccc.Script): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - // ... mutate tx ... - return tx; -} -``` - -### Pattern 2: Inline Header Fetching -**What:** Replace `getHeader(client, { type, value })` with direct CCC client calls -**When to use:** All call sites where `getHeader` or `tx.getHeader` was used -**Example:** -```typescript -// Before (standalone function): -const header = await getHeader(client, { type: "txHash", value: txHash }); - -// After (inlined): -const txWithHeader = await client.getTransactionWithHeader(txHash); -if (!txWithHeader?.header) { - throw new Error("Header not found"); -} -const header = txWithHeader.header; - -// Before (number lookup): -const header = await getHeader(client, { type: "number", value: blockNumber }); - -// After: -const header = await client.getHeaderByNumber(blockNumber); -if (!header) { - throw new Error("Header not found"); -} -``` - -### Pattern 3: Direct headerDeps Push (replacing addHeaders) -**What:** Push header hashes to `tx.headerDeps` directly with dedup -**When to use:** The 3 call sites where `tx.addHeaders()` was used -**Example:** -```typescript -// Before: -tx.addHeaders(depositHeader); // TransactionHeader with { header, txHash? } - -// After: -const hash = depositHeader.header.hash; -if (!tx.headerDeps.some((h) => h === hash)) { - tx.headerDeps.push(hash); -} -``` - -### Pattern 4: CCC DAO Error Class Convention -**What:** Error class in `transactionErrors.ts` following existing patterns -**When to use:** The new `ErrorNervosDaoOutputLimit` -**Example:** -```typescript -// Source: forks/ccc/packages/core/src/ckb/transactionErrors.ts -// Follow the ErrorTransactionInsufficientCapacity pattern: -export class ErrorNervosDaoOutputLimit extends Error { - public readonly count: number; - public readonly limit: number; - - constructor(count: number) { - super( - `NervosDAO transaction has ${count} output cells, exceeding the limit of 64`, - ); - this.count = count; - this.limit = 64; - } -} -``` - -### Pattern 5: DAO Check Utility Function -**What:** Standalone async utility + completeFee integration -**When to use:** Replacing all 7 scattered DAO checks -**Example:** -```typescript -// Standalone utility: -export async function assertDaoOutputLimit( - tx: Transaction, - client: Client, -): Promise { - if (tx.outputs.length <= 64) return; - - const { codeHash, hashType } = await client.getKnownScript( - KnownScript.NervosDao, - ); - const dao = Script.from({ codeHash, hashType, args: "0x" }); - - // Auto-resolve unresolved inputs - for (const input of tx.inputs) { - await input.completeExtraInfos(client); - } - - const isDaoTx = - tx.inputs.some((i) => i.cellOutput?.type?.eq(dao)) || - tx.outputs.some((o) => o.type?.eq(dao)); - - if (isDaoTx) { - throw new ErrorNervosDaoOutputLimit(tx.outputs.length); - } -} -``` - -### Pattern 6: addUdtHandlers Replacement -**What:** When SmartTransaction is removed, `addUdtHandlers()` calls can only do what `ccc.Transaction` supports -**When to use:** The 8 `addUdtHandlers` call sites across 4 files -**Example:** -```typescript -// Before: -tx.addUdtHandlers(this.udtHandler); - -// After (only the cellDeps part survives): -tx.addCellDeps(this.udtHandler.cellDeps); -// The UDT handler registration was SmartTransaction-specific. -// The cellDeps are the only persistent effect on a plain Transaction. -// Note: Most call sites already also call tx.addCellDeps(this.cellDeps) -// just before addUdtHandlers, so this may be a no-op if deduplication -// in addCellDeps handles it. Check each site. -``` - -### Anti-Patterns to Avoid -- **Partial script comparison:** Never compare just `codeHash`. Always use `Script.eq()` (codeHash + hashType + args). CCC's own `isNervosDao` uses codeHash + hashType but not args -- the new CCC utility should use the safer `Script.eq()` with args: "0x". -- **Leaving broken intermediate states:** Each feature-slice step must pass `pnpm check:full`. Don't delete SmartTransaction before all its consumers are updated. -- **Creating wrapper types:** Don't create a "TransactionWrapper" or similar -- use plain `ccc.Transaction` directly. -- **Keeping dead exports:** When `transaction.ts` is deleted, its barrel export `export * from "./transaction.js"` in `index.ts` must be removed in the same commit. -- **Redundant header caching:** Don't create a replacement header cache. CCC's `ClientCacheMemory` (128-block LRU) handles this transparently. - -## Don't Hand-Roll - -| Problem | Don't Build | Use Instead | Why | -|---------|-------------|-------------|-----| -| DAO profit calculation | Custom getInputsCapacity | CCC's native `Transaction.getInputsCapacity()` | Already handles DAO profit via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` | -| Header caching | Custom Map | CCC's `ClientCacheMemory` | Built-in LRU cache for 128 blocks, transparent to caller | -| Transaction type conversion | Custom `SmartTransaction.from()` | CCC's `Transaction.from(txLike)` | Standard pattern across CCC ecosystem; handles all TransactionLike variations | -| Cell finding | Custom CapacityManager.findCapacities | CCC's `client.findCells()` / `client.findCellsOnChain()` | Native CCC API with filter support | -| Fee completion | SmartTransaction.completeFee override | CCC's `tx.completeFeeBy()` / `tx.completeFeeChangeToLock()` | CCC provides multiple fee completion strategies | - -**Key insight:** SmartTransaction was created before CCC had many of these features. CCC now handles DAO profit, fee completion, cell finding, and caching natively. The abstraction layer is no longer needed. - -## Common Pitfalls - -### Pitfall 1: Breaking imports during staged deletion -**What goes wrong:** Deleting SmartTransaction from utils before consumers are updated causes cascading type errors across all 5 packages. -**Why it happens:** The dependency chain is utils -> dao -> core -> order -> sdk. Removing a type from utils breaks everything downstream. -**How to avoid:** Follow the 5-step execution order strictly. Update all consumers to use `ccc.TransactionLike` BEFORE deleting the SmartTransaction class. -**Warning signs:** TypeScript errors mentioning "SmartTransaction is not exported" in any package. - -### Pitfall 2: addUdtHandlers cellDeps duplication -**What goes wrong:** When replacing `addUdtHandlers`, the cellDeps are added twice (once by the explicit `tx.addCellDeps(this.cellDeps)` that usually precedes `addUdtHandlers`, and again when replacing `addUdtHandlers` itself). -**Why it happens:** Most call sites already have `tx.addCellDeps(this.cellDeps)` right before `tx.addUdtHandlers(this.udtHandler)`. The `addUdtHandlers` internally also calls `this.addCellDeps(udtHandler.cellDeps)`. -**How to avoid:** Audit each `addUdtHandlers` call site to check if the cellDeps are already added by a preceding `addCellDeps`. CCC's `addCellDeps` deduplicates, so double-adding is harmless but messy. -**Warning signs:** Duplicate cellDeps in transaction output (functional but wasteful). - -### Pitfall 3: Missing null checks when inlining getHeader -**What goes wrong:** `client.getTransactionWithHeader(hash)` returns `undefined` if the transaction is not found. The original `getHeader` had a null check + throw. -**Why it happens:** Inlining the CCC client call without preserving the error path. -**How to avoid:** Always include `if (!result?.header) throw new Error("Header not found")` at each inlined call site. -**Warning signs:** Runtime `Cannot read property 'epoch' of undefined` errors. - -### Pitfall 4: headerDeps dedup logic -**What goes wrong:** When replacing `addHeaders`, pushing the same header hash twice to `tx.headerDeps`. -**Why it happens:** `addHeaders` had dedup logic (`if (!this.headerDeps.some((h) => h === hash))`). Inlining without preserving the check. -**How to avoid:** Always include the dedup check before `tx.headerDeps.push(hash)`. -**Warning signs:** Duplicate entries in `headerDeps`, which could cause verification failures on-chain. - -### Pitfall 5: TransactionHeader type still needed by DaoCell -**What goes wrong:** Deleting SmartTransaction's `TransactionHeader` interface breaks `DaoCell.headers` and `ReceiptCell.header`. -**Why it happens:** `TransactionHeader` is defined in `transaction.ts` (being deleted) but used by `@ickb/dao` and `@ickb/core`. -**How to avoid:** The `TransactionHeader` interface (`{ header: ccc.ClientBlockHeader, txHash?: ccc.Hex }`) must be moved to a surviving file (e.g., `utils.ts`) or its definition inlined where used. This interface is still needed even after SmartTransaction is gone -- `DaoCell.headers` is a tuple of `[TransactionHeader, TransactionHeader]`. -**Warning signs:** "TransactionHeader is not exported" errors after deleting transaction.ts. - -### Pitfall 6: SmartTransaction.getInputsCapacity vs tx.getHeader -**What goes wrong:** SmartTransaction's `getInputsCapacity` override (lines 154-202) uses `this.getHeader()` (the instance method). When SmartTransaction is deleted, this override disappears. But CCC's native `Transaction.getInputsCapacity()` already handles DAO profit differently. -**Why it happens:** The override was written before CCC added native DAO profit calculation. -**How to avoid:** Verify that CCC's native `getInputsCapacity()` handles all cases that SmartTransaction's override did. CCC's version uses `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` which resolves headers through the client. This is functionally equivalent. -**Warning signs:** Incorrect fee calculation after SmartTransaction removal (would manifest in over/under-paying fees). - -### Pitfall 7: IckbUdtManager.getInputsUdtBalance uses tx.getHeader -**What goes wrong:** `IckbUdtManager.getInputsUdtBalance` (core/src/udt.ts lines 108, 125) calls `tx.getHeader()` which is a SmartTransaction instance method. After SmartTransaction is removed, this call doesn't exist on plain `ccc.Transaction`. -**Why it happens:** The method relies on SmartTransaction's header cache + headerDeps validation. -**How to avoid:** Replace `tx.getHeader(client, { type: "txHash", value: outPoint.txHash })` with inlined CCC client calls. The headerDeps validation from the old `getHeader` instance method was a runtime check that headers were pre-populated -- after removal, the client call fetches headers directly. -**Warning signs:** TypeScript error `Property 'getHeader' does not exist on type 'Transaction'`. - -### Pitfall 8: forks/ccc pins must be recorded after CCC changes -**What goes wrong:** Making changes to `forks/ccc/` without running `bash forks/forker/record.sh ccc` means the pins don't reflect the new state. -**Why it happens:** `forks/.pin/ccc/` contains an integrity check. If ccc code changes but pins don't update, replay won't reproduce the same state. -**How to avoid:** After developing the DAO utility in `forks/ccc/`, run `bash forks/forker/record.sh ccc` to update pins. Check `bash forks/forker/status.sh ccc` to verify. -**Warning signs:** `bash forks/forker/status.sh ccc` reports exit code 1 (pending work). - -## Code Examples - -### Complete DAO Check Replacement Pattern -```typescript -// Source: Verified from forks/ccc/packages/core/src/ckb/transaction.ts -// and packages/dao/src/dao.ts - -// Before (scattered in 7 locations): -if (tx.outputs.length > 64) { - throw new Error("More than 64 output cells in a NervosDAO transaction"); -} - -// After (calling CCC utility -- requires async context): -await assertDaoOutputLimit(tx, client); - -// For sync contexts (where client is not available), -// the check can be done at completeFee time as a safety net. -``` - -### Method Signature Migration Pattern -```typescript -// Before (dao/src/dao.ts DaoManager.deposit): -deposit( - tx: SmartTransaction, - capacities: ccc.FixedPoint[], - lock: ccc.Script, -): void { - tx.addCellDeps(this.cellDeps); - // ... -} - -// After: -deposit( - txLike: ccc.TransactionLike, - capacities: ccc.FixedPoint[], - lock: ccc.Script, -): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - tx.addCellDeps(this.cellDeps); - // ... - return tx; -} -``` - -### CapacityManager Replacement in SDK -```typescript -// Before (sdk/src/sdk.ts, line 376): -for await (const c of this.capacity.findCapacities(client, this.bots, opts)) { - // ... -} - -// After (using CCC's native cell finding): -for (const lock of unique(this.bots)) { - for await (const cell of client.findCellsOnChain( - { - script: lock, - scriptType: "lock", - filter: { - scriptLenRange: [0n, 1n], - }, - scriptSearchMode: "exact", - withData: true, - }, - "asc", - 400, - )) { - if (cell.cellOutput.type !== undefined || !cell.cellOutput.lock.eq(lock)) { - continue; - } - // ... rest of logic using cell directly - } -} -``` - -### CCC Vitest Test Pattern -```typescript -// Source: forks/ccc/packages/core/src/ckb/transaction.test.ts -import { beforeEach, describe, expect, it, vi } from "vitest"; -import { ccc } from "../index.js"; - -describe("assertDaoOutputLimit", () => { - let client: ccc.Client; - - beforeEach(async () => { - client = new ccc.ClientPublicTestnet(); - }); - - it("should not throw when outputs <= 64", async () => { - const tx = ccc.Transaction.default(); - // Add 64 outputs - for (let i = 0; i < 64; i++) { - tx.addOutput({ lock: /* ... */ }); - } - await expect(assertDaoOutputLimit(tx, client)).resolves.not.toThrow(); - }); - - it("should throw ErrorNervosDaoOutputLimit when DAO tx has > 64 outputs", async () => { - // ... mock setup with DAO cells - await expect(assertDaoOutputLimit(tx, client)).rejects.toThrow( - ErrorNervosDaoOutputLimit, - ); - }); -}); -``` - -## State of the Art - -| Old Approach | Current Approach | When Changed | Impact | -|--------------|------------------|--------------|--------| -| SmartTransaction extends Transaction | Plain ccc.Transaction + utilities | This phase | All method signatures change to TransactionLike | -| Custom getInputsCapacity override | CCC native getInputsCapacity with DAO profit | CCC core update (PR #260, merged) | Override in SmartTransaction is redundant | -| Custom header cache (Map) | CCC ClientCacheMemory LRU (128 blocks) | CCC core feature | No manual header management needed | -| Scattered DAO output checks | Centralized CCC utility | This phase | Single source of truth for the 64-output limit | -| Custom CapacityManager.findCapacities | CCC client.findCells/findCellsOnChain | CCC core feature | Direct client API is sufficient | - -**Deprecated/outdated:** -- `SmartTransaction.getInputsUdtBalance` / `getOutputsUdtBalance`: Use `@ckb-ccc/udt` Udt class methods instead (Phase 4-5) -- `ccc.udtBalanceFrom`: Deprecated, replaced by `@ckb-ccc/udt` (tracked in SMTX-10, Phase 4-5) -- `ccc.ErrorTransactionInsufficientCoin`: Deprecated, replaced by `ErrorUdtInsufficientCoin` from `@ckb-ccc/udt` - -## Detailed Inventory - -### SmartTransaction Consumer Map (9 files) - -| File | Usage | Migration | -|------|-------|-----------| -| `packages/utils/src/transaction.ts` | Class definition | **DELETE** entire file | -| `packages/utils/src/capacity.ts` | `addCapacities(tx: SmartTransaction, ...)` | **DELETE** entire file | -| `packages/utils/src/udt.ts` | `UdtHandler` interface + `UdtManager` methods accept `SmartTransaction` | Update signatures to `ccc.TransactionLike` | -| `packages/dao/src/dao.ts` | `DaoManager.deposit/requestWithdrawal/withdraw(tx: SmartTransaction, ...)` | Update signatures to `ccc.TransactionLike` | -| `packages/core/src/logic.ts` | `LogicManager.deposit/completeDeposit(tx: SmartTransaction, ...)` | Update signatures to `ccc.TransactionLike` | -| `packages/core/src/owned_owner.ts` | `OwnedOwnerManager.requestWithdrawal/withdraw(tx: SmartTransaction, ...)` | Update signatures to `ccc.TransactionLike` | -| `packages/core/src/udt.ts` | `IckbUdtManager.getInputsUdtBalance(client, tx: SmartTransaction)` | Update signature to `ccc.TransactionLike` | -| `packages/order/src/order.ts` | `OrderManager.mint/addMatch/melt(tx: SmartTransaction, ...)` | Update signatures to `ccc.TransactionLike` | -| `packages/sdk/src/sdk.ts` | `IckbSdk.request/collect(tx: SmartTransaction, ...)` | Update signatures to `ccc.TransactionLike` | - -### getHeader Call Sites (9 total) - -**Standalone function `getHeader()` (5 sites):** - -| File | Line | Key Type | Replacement | -|------|------|----------|-------------| -| `packages/dao/src/cells.ts` | 91 | `number` | `client.getHeaderByNumber(mol.Uint64LE.decode(cell.outputData))` | -| `packages/dao/src/cells.ts` | 97 | `txHash` | `(await client.getTransactionWithHeader(txHash))?.header` | -| `packages/dao/src/cells.ts` | 109 | `txHash` | `(await client.getTransactionWithHeader(txHash))?.header` | -| `packages/core/src/cells.ts` | 84 | `txHash` | `(await client.getTransactionWithHeader(txHash))?.header` | -| `packages/sdk/src/sdk.ts` | 388 | `txHash` | `(await client.getTransactionWithHeader(c.cell.outPoint.txHash))?.header` | - -**Instance method `tx.getHeader()` (4 sites -- deleted with SmartTransaction):** - -| File | Line | Key Type | Replacement | -|------|------|----------|-------------| -| `packages/utils/src/transaction.ts` | 185 | `txHash` | Deleted with SmartTransaction (CCC handles natively) | -| `packages/utils/src/transaction.ts` | 190 | `number` | Deleted with SmartTransaction (CCC handles natively) | -| `packages/core/src/udt.ts` | 108 | `txHash` | `(await client.getTransactionWithHeader(outPoint.txHash))?.header` | -| `packages/core/src/udt.ts` | 125 | `txHash` | `(await client.getTransactionWithHeader(outPoint.txHash))?.header` | - -### addHeaders Call Sites (3 sites) - -| File | Line | What It Pushes | Replacement | -|------|------|----------------|-------------| -| `packages/dao/src/dao.ts` | 160 | Single `depositHeader` TransactionHeader | Push `depositHeader.header.hash` to `tx.headerDeps` with dedup | -| `packages/dao/src/dao.ts` | 216 | Array of `headers` (from DaoCell) | Push each `header.header.hash` to `tx.headerDeps` with dedup | -| `packages/core/src/logic.ts` | 125 | Array of receipt headers | Push each `r.header.header.hash` to `tx.headerDeps` with dedup | - -### 64-Output DAO Check Locations (7 sites) - -| File | Line | Context | -|------|------|---------| -| `packages/utils/src/transaction.ts` | 93-95 | SmartTransaction.completeFee (async, has client) | -| `packages/dao/src/dao.ts` | 100-102 | DaoManager.deposit (sync) | -| `packages/dao/src/dao.ts` | 174-176 | DaoManager.requestWithdrawal (sync) | -| `packages/dao/src/dao.ts` | 245-247 | DaoManager.withdraw (sync) | -| `packages/core/src/logic.ts` | 106-108 | LogicManager.deposit (sync) | -| `packages/core/src/owned_owner.ts` | 104-106 | OwnedOwnerManager.requestWithdrawal (sync) | -| `packages/core/src/owned_owner.ts` | 146-148 | OwnedOwnerManager.withdraw (sync) | - -**Note on sync vs async:** 6 of 7 check locations are in sync methods. The CCC `assertDaoOutputLimit` is async (needs client for `getKnownScript`). Options: (a) make the caller methods async, (b) pass the DAO script as a parameter so the check can remain sync, or (c) keep a simple sync `outputs.length > 64` check at the sync sites and use the async utility in completeFee. Option (a) is cleanest since these methods do IO-adjacent work. - -### addUdtHandlers Call Sites (8 sites) - -| File | Line | Preceding addCellDeps? | Safe to just remove? | -|------|------|------------------------|---------------------| -| `packages/core/src/owned_owner.ts` | 88 | Yes (line 87: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/core/src/owned_owner.ts` | 135 | Yes (line 134: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/core/src/logic.ts` | 87 | Yes (line 86: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/core/src/logic.ts` | 123 | Yes (line 122: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/utils/src/udt.ts` | 282 | Yes (line 281: `tx.addCellDeps(this.cellDeps)`) | Self-registering; replace with `tx.addCellDeps(this.cellDeps)` (already done on line 281) | -| `packages/order/src/order.ts` | 191 | Yes (line 190: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/order/src/order.ts` | 228 | Yes (line 227: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | -| `packages/order/src/order.ts` | 516 | Yes (line 515: `tx.addCellDeps(this.cellDeps)`) | Need `tx.addCellDeps(this.udtHandler.cellDeps)` | - -**Analysis:** Each `addUdtHandlers` call does two things: (1) registers the handler in `udtHandlers` Map (SmartTransaction-specific, lost), (2) calls `addCellDeps(udtHandler.cellDeps)`. After SmartTransaction removal, replace with `tx.addCellDeps(this.udtHandler.cellDeps)` at each site. The UDT handler registration is only consumed by SmartTransaction's overridden `getInputsUdtBalance`/`getOutputsUdtBalance`/`completeFee` -- which are all being deleted. - -### TransactionHeader Type Preservation - -`TransactionHeader` (defined in `transaction.ts` line 506-517) is imported by: -- `packages/dao/src/cells.ts` (DaoCell.headers, daoCellFrom) -- `packages/core/src/cells.ts` (ReceiptCell.header, receiptCellFrom) - -This interface must be moved to a surviving file before `transaction.ts` is deleted. Candidate: `utils.ts` (it already contains `HeaderKey` which is being removed, so there's precedent for header-related types there). Alternatively, define it inline in each consumer. The interface is simple: `{ header: ccc.ClientBlockHeader, txHash?: ccc.Hex }`. - -### CapacityManager Consumer Map (3 files) - -| File | Usage | Migration | -|------|-------|-----------| -| `packages/utils/src/capacity.ts` | Class definition | **DELETE** entire file | -| `packages/sdk/src/sdk.ts` | `this.capacity.findCapacities(client, this.bots, opts)` | Inline CCC `client.findCellsOnChain()` with appropriate filters | -| `packages/sdk/src/constants.ts` | `CapacityManager.withAnyData()` constructor + return type | Remove from getConfig return type; remove instantiation | - -## Open Questions - -1. **Sync DAO check after utility migration** - - What we know: 6 of 7 scattered checks are in sync methods. The CCC `assertDaoOutputLimit` is async. - - What's unclear: Should all 6 sync methods become async to call the CCC utility, or should they accept a pre-resolved DAO script? - - Recommendation: Make the iCKB methods async (they already return void and do other mutations). Alternatively, the methods could accept an optional `client` parameter. The user's CONTEXT.md execution order puts "Replace all scattered DAO checks with CCC utility calls" as step 2, implying all checks become calls to the CCC utility. Making the methods async is the cleanest path. - -2. **Return type change: void -> Transaction** - - What we know: CCC convention returns `ccc.Transaction`. Current methods return `void` (mutating in-place). - - What's unclear: Changing return types from `void` to `ccc.Transaction` changes the API contract even if callers can ignore the return. - - Recommendation: Change return types to `ccc.Transaction` per CCC convention. Since these are library methods (not callback interfaces), callers can adapt. The `TransactionLike` input already forces callers to think about the pattern. - -3. **DaoCell.headers and TransactionHeader after removal** - - What we know: `TransactionHeader` is used by DaoCell (dao package) and ReceiptCell (core package). It's defined in transaction.ts (being deleted). - - What's unclear: Should the type be moved to utils.ts, or should it be relocated to the dao package where it's most used? - - Recommendation: Move to `utils.ts` since both dao and core import from `@ickb/utils`. The type is simple and doesn't create unwanted coupling. - -## Sources - -### Primary (HIGH confidence) -- Codebase source files in `/workspaces/stack/packages/` -- all SmartTransaction consumers, getHeader call sites, DAO checks inventoried directly -- CCC source in `/workspaces/stack/forks/ccc/packages/core/src/` -- Transaction class, TransactionLike type, error patterns, completeFee implementation, getInputsCapacity, test patterns -- `.planning/phases/01-ickb-utils-smarttransaction-removal/01-CONTEXT.md` -- User decisions and constraints -- `.planning/REQUIREMENTS.md` -- Requirement definitions and traceability - -### Secondary (MEDIUM confidence) -- CCC's `Cell.isNervosDao()` implementation (line 415-437) -- shows CCC pattern for DAO detection (uses codeHash + hashType, not full Script.eq()) -- CCC's vitest configuration and test patterns -- from `vitest.config.mts` and `transaction.test.ts` - -## Metadata - -**Confidence breakdown:** -- Standard stack: HIGH -- verified directly from codebase and CCC source -- Architecture: HIGH -- all patterns verified from CCC source and existing iCKB code -- Pitfalls: HIGH -- identified from direct code analysis, not speculation -- Inventory: HIGH -- all call sites counted by direct grep, every file read - -**Research date:** 2026-02-22 -**Valid until:** 2026-03-22 (stable codebase, locked decisions) diff --git a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-VERIFICATION.md b/.planning/phases/01-ickb-utils-smarttransaction-removal/01-VERIFICATION.md deleted file mode 100644 index 1b8a54c..0000000 --- a/.planning/phases/01-ickb-utils-smarttransaction-removal/01-VERIFICATION.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -phase: 01-ickb-utils-smarttransaction-removal -verified: 2026-02-22T17:30:00Z -status: passed -score: 6/6 must-haves verified -re_verification: false ---- - -# Phase 1: SmartTransaction Removal (feature-slice) Verification Report - -**Phase Goal**: SmartTransaction class, CapacityManager class are deleted; all manager method signatures across all 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`; 64-output DAO limit check is contributed to CCC core; `getHeader()`/`HeaderKey` are removed and inlined. Each removal is chased across all packages — build stays green at every step. - -**Verified**: 2026-02-22T17:30:00Z -**Status**: passed -**Re-verification**: No — initial verification - -## Goal Achievement - -### Observable Truths (from ROADMAP.md Success Criteria) - -| # | Truth | Status | Evidence | -|---|-------|--------|----------| -| 1 | `SmartTransaction` class and `CapacityManager` class no longer exist in `@ickb/utils` source or exports | VERIFIED | `packages/utils/src/transaction.ts` and `packages/utils/src/capacity.ts` are deleted; `packages/utils/src/index.ts` exports only `codec.js`, `heap.js`, `udt.js`, `utils.js`; `grep SmartTransaction packages/ apps/` returns zero results | -| 2 | `UdtHandler` interface and `UdtManager` class remain in `@ickb/utils` with method signatures updated from `SmartTransaction` to `ccc.TransactionLike` | VERIFIED | `packages/utils/src/udt.ts` exports both `UdtHandler` interface and `UdtManager` class; all methods accept `txLike: ccc.TransactionLike` and convert with `ccc.Transaction.from(txLike)` at entry | -| 3 | `getHeader()` function and `HeaderKey` type are removed from `@ickb/utils`; all call sites inline CCC client calls; `SmartTransaction.addHeaders()` call sites push to `tx.headerDeps` directly | VERIFIED | `grep getHeader packages/utils/src/` returns zero results; `grep HeaderKey packages/` returns zero results; `grep addHeaders packages/` returns zero results; all 7 call sites replaced with `client.getTransactionWithHeader()` / `client.getHeaderByNumber()` with null-check-and-throw; 3 `headerDeps.push()` sites with `.some()` dedup in `dao/dao.ts` and `core/logic.ts` | -| 4 | A 64-output NervosDAO limit check exists in CCC core: `completeFee()` safety net, standalone async utility, and `ErrorNervosDaoOutputLimit` error class; all 6+ scattered checks replaced | VERIFIED | `ErrorNervosDaoOutputLimit` in `forks/ccc/packages/core/src/ckb/transactionErrors.ts` with `count` and `limit` fields; `assertDaoOutputLimit` exported from `forks/ccc/packages/core/src/ckb/transaction.ts`; called at lines 2257 and 2285 in `completeFee`; called in `packages/dao/src/dao.ts` (3×), `packages/core/src/logic.ts` (1×), `packages/core/src/owned_owner.ts` (2×); `grep "outputs.length > 64" packages/` returns zero results | -| 5 | ALL manager method signatures across ALL 5 library packages accept `ccc.TransactionLike` instead of `SmartTransaction`, following CCC's convention (TransactionLike input, Transaction output with `Transaction.from()` conversion at entry point) | VERIFIED | `txLike: ccc.TransactionLike` present in dao, core/logic, core/owned_owner, core/udt, order, sdk, and utils/udt; `ccc.Transaction.from(txLike)` at entry in all 15 confirmed conversion points; `return tx;` present at all method exits across dao, core, order, sdk; `addUdtHandlers` fully removed, replaced with `tx.addCellDeps(this.udtHandler.cellDeps)` at 7 sites | -| 6 | `pnpm check` passes after each feature-slice removal step — no intermediate broken states | VERIFIED | All 5 plans committed atomically with individual task commits (7081869, 2decd06, 85ead3a, 2e832ae, de8f4a7); `pnpm check` passes on current state (confirmed by build execution: all 5 packages compile clean) | - -**Score**: 6/6 truths verified - -### Required Artifacts - -| Artifact | Expected | Status | Details | -|----------|----------|--------|---------| -| `forks/ccc/packages/core/src/ckb/transactionErrors.ts` | `ErrorNervosDaoOutputLimit` error class with `count` and `limit` fields | VERIFIED | Class exists, `public readonly count: number` and `public readonly limit: number` confirmed | -| `forks/ccc/packages/core/src/ckb/transaction.ts` | `assertDaoOutputLimit` utility + `completeFee` safety net | VERIFIED | Function at line 2465, called in `completeFee` at lines 2257 and 2285 | -| `packages/utils/src/utils.ts` | `TransactionHeader` type preserved; `getHeader` and `HeaderKey` absent | VERIFIED | `TransactionHeader` interface at line 19; no `getHeader` function or `HeaderKey` type found | -| `packages/utils/src/index.ts` | Barrel exports without `transaction.js` or `capacity.js` | VERIFIED | Exports only `codec.js`, `heap.js`, `udt.js`, `utils.js` | -| `packages/utils/src/udt.ts` | `UdtHandler` interface and `UdtManager` class with `TransactionLike` signatures | VERIFIED | Both present; all methods accept `txLike: ccc.TransactionLike` | -| `packages/dao/src/cells.ts` | Inlined CCC client calls for header fetching | VERIFIED | `client.getHeaderByNumber()` and `client.getTransactionWithHeader()` with null checks confirmed | -| `packages/core/src/cells.ts` | Inlined CCC client calls for header fetching | VERIFIED | `client.getTransactionWithHeader()` with null check confirmed | -| `packages/dao/src/dao.ts` | TransactionLike signatures + assertDaoOutputLimit calls + headerDeps push | VERIFIED | 3× `txLike: ccc.TransactionLike`, 3× `assertDaoOutputLimit`, 2× `headerDeps.push` with dedup | -| `packages/core/src/logic.ts` | TransactionLike signature + assertDaoOutputLimit call + headerDeps push | VERIFIED | `txLike: ccc.TransactionLike`, `assertDaoOutputLimit` at line 105, `headerDeps.push` at line 130 with dedup | -| `packages/core/src/owned_owner.ts` | TransactionLike signatures + assertDaoOutputLimit calls | VERIFIED | 2× `txLike: ccc.TransactionLike`, 2× `assertDaoOutputLimit` | -| `packages/core/src/udt.ts` | TransactionLike signature, inlined CCC client calls | VERIFIED | `txLike: ccc.TransactionLike`, 2× `client.getTransactionWithHeader()` with null checks | -| `packages/order/src/order.ts` | TransactionLike signatures | VERIFIED | 3× `txLike: ccc.TransactionLike`, `ccc.Transaction.from(txLike)` at each entry | -| `packages/sdk/src/sdk.ts` | TransactionLike signatures + findCellsOnChain (replacing CapacityManager) | VERIFIED | 2× `txLike: ccc.TransactionLike`; `findCellsOnChain` at line 373 with `scriptLenRange` filter; `getTransactionWithHeader` with null check at line 401 | -| `packages/utils/src/transaction.ts` | DELETED | VERIFIED | File does not exist | -| `packages/utils/src/capacity.ts` | DELETED | VERIFIED | File does not exist | -| `forks/.pin/ccc/` | Local patches for deterministic CCC replay | VERIFIED | Pins directory with multi-file format (manifest + resolutions + patches) | - -### Key Link Verification (from PLAN frontmatter) - -| From | To | Via | Status | Details | -|------|----|-----|--------|---------| -| `packages/dao/src/dao.ts` | CCC `assertDaoOutputLimit` | `ccc.assertDaoOutputLimit(tx, client)` | WIRED | Pattern `ccc.assertDaoOutputLimit` found 3× | -| `packages/core/src/logic.ts` | CCC `assertDaoOutputLimit` | `ccc.assertDaoOutputLimit(tx, client)` | WIRED | Pattern found 1× at line 105 | -| `packages/core/src/owned_owner.ts` | CCC `assertDaoOutputLimit` | `ccc.assertDaoOutputLimit(tx, client)` | WIRED | Pattern found 2× at lines 109, 150 | -| `packages/dao/src/cells.ts` | CCC Client API | `client.get(TransactionWithHeader|HeaderByNumber)` | WIRED | All 3 patterns found with null checks and throws | -| `packages/core/src/udt.ts` | CCC Client API | `client.getTransactionWithHeader` | WIRED | Pattern found 2× at lines 104, 124 | -| `packages/dao/src/dao.ts` | `tx.headerDeps` | `headerDeps.push` | WIRED | Pattern found 2×: lines 163, 222 with `.some()` dedup | -| `packages/dao/src/dao.ts` | `ccc.Transaction.from()` | `Transaction.from(txLike)` at method entry | WIRED | Pattern found 3× at lines 82, 128, 198 | -| `packages/order/src/order.ts` | `ccc.Transaction.from()` | `Transaction.from(txLike)` at method entry | WIRED | Pattern found 3× at lines 179, 223, 511 | -| `packages/sdk/src/sdk.ts` | `client.findCellsOnChain` | CapacityManager replacement | WIRED | `findCellsOnChain` at line 373 | - -### Requirements Coverage - -| Requirement | Source Plan | Description | Status | Evidence | -|-------------|------------|-------------|--------|----------| -| SMTX-01 | 01-03-PLAN.md | All manager method signatures accept `ccc.TransactionLike` instead of `SmartTransaction`; `CapacityManager` deleted | SATISFIED | `txLike: ccc.TransactionLike` present in all 5 library packages across 20+ method signatures; `capacity.ts` deleted | -| SMTX-02 | 01-03-PLAN.md | `SmartTransaction` class and its `completeFee()` override deleted from `@ickb/utils` | SATISFIED | `transaction.ts` deleted; zero `SmartTransaction` references anywhere in `packages/` or `apps/` | -| SMTX-04 | 01-02-PLAN.md | `getHeader()` and `HeaderKey` removed from `@ickb/utils`; all call sites inline CCC client calls | SATISFIED | Zero `getHeader`/`HeaderKey` references in `packages/utils/src/`; all 7 call sites inline `client.getTransactionWithHeader()` or `client.getHeaderByNumber()` with null-check-throws | -| SMTX-05 | 01-03-PLAN.md | UDT handler registration (`addUdtHandlers()`) replaced | SATISFIED | Zero `addUdtHandlers` references in `packages/`; 7 replacement sites use `tx.addCellDeps(this.udtHandler.cellDeps)` — note: `UdtHandler`/`UdtManager` themselves are preserved (removal deferred to Phase 4-5 as documented in REQUIREMENTS.md traceability) | -| SMTX-06 | 01-01-PLAN.md | 64-output NervosDAO limit check consolidated into single utility | SATISFIED | `assertDaoOutputLimit` in CCC core; `ErrorNervosDaoOutputLimit` in CCC core; zero inline `outputs.length > 64` checks in `packages/`; called from 6 sites across dao/core | - -**Note on SMTX-05 scope**: REQUIREMENTS.md marks SMTX-05 as Complete at Phase 1 with the note "addUdtHandlers() replaced with tx.addCellDeps(udtHandler.cellDeps) (01-03); UdtHandler/UdtManager replacement deferred to Phase 4-5". This is correct — the handler registration is replaced but the classes themselves are intentionally preserved for Phase 3+ investigation. - -**Note on SMTX-06 count**: The plan cited "all 7 scattered checks" but 6 call sites were found in actual packages (3 in `dao.ts`, 1 in `logic.ts`, 2 in `owned_owner.ts`). The 7th was in `SmartTransaction.completeFee` (packages/utils/src/transaction.ts), which is now deleted — the CCC `completeFee` safety net (2 call sites) now covers that responsibility. This is correct behaviour. - -### Anti-Patterns Found - -None found. Specific scans conducted: - -- `grep -rn "TODO|FIXME|PLACEHOLDER" packages/` (non-dist): No results in modified files. -- `grep -rn "return null|return \{\}" packages/` on new code: No stub patterns. -- `grep "outputs.length > 64" packages/`: Zero results (old inline checks fully removed). -- `grep "SmartTransaction" packages/ apps/`: Zero results. -- `grep "CapacityManager" packages/ apps/`: Zero results. -- `grep "addUdtHandlers" packages/`: Zero results. -- `grep "HeaderKey" packages/`: Zero results. -- `grep "getHeader\b" packages/ apps/` (non-dist): Zero results. -- `grep "addHeaders" packages/`: Zero results. - -### Human Verification Required - -None. All success criteria are statically verifiable: - -- File existence/deletion: verified with `ls`. -- Class/function presence: verified with `grep`. -- Build status: verified with `pnpm check` (passed — all 5 packages compiled clean). -- Commit hash existence: all 5 task commits confirmed in `git log`. - -### Gaps Summary - -No gaps. All 6 observable truths are fully verified. - -All 5 library packages (`@ickb/utils`, `@ickb/dao`, `@ickb/order`, `@ickb/core`, `@ickb/sdk`) compile with zero type errors under strict TypeScript settings after the changes. The `pnpm check` script (clean, install, lint, build, test) passed on the current state of the repository. - ---- - -_Verified: 2026-02-22T17:30:00Z_ -_Verifier: AI Coworker (gsd-verifier)_ diff --git a/.planning/phases/02-ccc-utility-adoption/02-01-PLAN.md b/.planning/phases/02-ccc-utility-adoption/02-01-PLAN.md deleted file mode 100644 index f34655f..0000000 --- a/.planning/phases/02-ccc-utility-adoption/02-01-PLAN.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -phase: 02-ccc-utility-adoption -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - packages/utils/src/utils.ts - - packages/order/src/entities.ts - - packages/sdk/src/codec.ts - - packages/order/src/order.ts - - packages/sdk/src/sdk.ts - - apps/faucet/src/main.ts -autonomous: true -requirements: - - DEDUP-01 - - DEDUP-02 - - DEDUP-03 - - DEDUP-04 - - DEDUP-05 - -must_haves: - truths: - - "All call sites using local max()/min() now use Math.max()/Math.min() (number-typed contexts) and the local implementations are deleted" - - "The single gcd() call site uses ccc.gcd() and the local implementation is deleted" - - "Local isHex() and hexFrom() are deleted from @ickb/utils" - - "All hexFrom() call sites use entity.toHex() for Entity args and ccc.hexFrom() for BytesLike args" - - "iCKB-unique utilities (binarySearch, asyncBinarySearch, shuffle, unique, collect, BufferedGenerator, MinHeap, sum) remain in @ickb/utils unchanged in signature" - - "unique() internal implementation updated from hexFrom(i) to i.toHex()" - - "pnpm check:full passes with zero errors" - artifacts: - - path: "packages/utils/src/utils.ts" - provides: "Utility module with local max/min/gcd/hexFrom/isHex deleted, unique() updated" - contains: "i.toHex()" - - path: "packages/order/src/entities.ts" - provides: "Order entities with CCC utility calls" - contains: "ccc.gcd" - - path: "packages/sdk/src/codec.ts" - provides: "SDK codec with Math.max replacing local max" - contains: "Math.max" - key_links: - - from: "packages/order/src/entities.ts" - to: "@ckb-ccc/core" - via: "ccc.gcd() call; Math.max() for number-typed max" - pattern: "ccc\\.gcd|Math\\.max" - - from: "packages/sdk/src/codec.ts" - to: "@ckb-ccc/core" - via: "Math.max() replacing local max (number-typed context)" - pattern: "Math\\.max" - - from: "packages/utils/src/utils.ts" - to: "@ckb-ccc/core" - via: "unique() uses entity.toHex() instead of deleted hexFrom()" - pattern: "i\\.toHex\\(\\)" ---- - - -Replace five local utility functions (max, min, gcd, hexFrom, isHex) in @ickb/utils with their CCC equivalents at all call sites, update the unique() internal implementation, delete the local function definitions, and verify iCKB-unique utilities remain intact. - -Purpose: Eliminate duplicated functionality with CCC core -- local copies diverge over time and create maintenance burden. -Output: All packages and apps compile cleanly with CCC utility calls instead of local wrappers. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/02-ccc-utility-adoption/02-RESEARCH.md - - - - - - Task 1: Replace all external call sites with CCC equivalents - - packages/order/src/entities.ts - packages/sdk/src/codec.ts - packages/order/src/order.ts - packages/sdk/src/sdk.ts - apps/faucet/src/main.ts - - -Replace every external call site of the five local utility functions with CCC equivalents. The exact replacements are: - -**max() -- 2 call sites (DEDUP-01):** -1. `packages/order/src/entities.ts` line ~172: `max(aScale.toString(2).length, bScale.toString(2).length)` becomes `Math.max(aScale.toString(2).length, bScale.toString(2).length)`. Remove `max` from the `@ickb/utils` import. -2. `packages/sdk/src/codec.ts` line ~80: `max(1, ...bins)` becomes `Math.max(1, ...bins)`. Remove `max` from the `@ickb/utils` import (this may make the import empty or removable). - -**gcd() -- 1 call site (DEDUP-02):** -1. `packages/order/src/entities.ts` line ~167: `gcd(aScale, bScale)` becomes `ccc.gcd(aScale, bScale)`. Remove `gcd` from the `@ickb/utils` import. Note: CCC's gcd returns `Num` (bigint), same type as current usage -- direct drop-in. - -**hexFrom() -- 5 external call sites (DEDUP-04):** -1. `packages/sdk/src/sdk.ts` line ~393: `hexFrom(cell.cellOutput.lock)` becomes `cell.cellOutput.lock.toHex()`. Remove `hexFrom` from the `@ickb/utils` import. -2. `packages/sdk/src/sdk.ts` line ~423: `hexFrom(wr.owner.cell.cellOutput.lock)` becomes `wr.owner.cell.cellOutput.lock.toHex()`. (Same import fix as above.) -3. `packages/order/src/order.ts` line ~560: `hexFrom(master.cell.outPoint)` becomes `master.cell.outPoint.toHex()`. Remove `hexFrom` from the `@ickb/utils` import. -4. `packages/order/src/order.ts` line ~572: `hexFrom(master)` becomes `master.toHex()`. (Same import fix as above.) -5. `apps/faucet/src/main.ts` line ~20: `hexFrom(getRandomValues(new Uint8Array(32)))` becomes `ccc.hexFrom(getRandomValues(new Uint8Array(32)))`. Remove `hexFrom` from the `@ickb/utils` import. Add `import { ccc } from "@ckb-ccc/core";` if not already present. - -After all replacements, clean up imports: remove `max`, `min`, `gcd`, `hexFrom`, `isHex` from all `@ickb/utils` import statements. If an import statement becomes empty, delete it entirely. If it still has other symbols (e.g., `CheckedInt32LE`, `unique`, `sum`), keep only those. - -IMPORTANT: Use `import type` for type-only imports per `verbatimModuleSyntax`. All functions must have explicit return type annotations per ESLint rules. - - -Run `pnpm -r --filter './packages/**' --filter './apps/faucet' exec tsc --noEmit` to verify all modified packages compile. No import errors for removed symbols. - - -All 8 external call sites (2 max, 1 gcd, 5 hexFrom) replaced with CCC equivalents. Zero references to local max/min/gcd/hexFrom/isHex remain in any file outside packages/utils/src/utils.ts. - - - - - Task 2: Update unique() internals, delete local functions, generate changeset, and verify - - packages/utils/src/utils.ts - - -**Step 1: Update `unique()` internal call (DEDUP-05 preservation):** -In `packages/utils/src/utils.ts`, inside the `unique()` function (line ~349), change: -```typescript -const key = hexFrom(i); -``` -to: -```typescript -const key = i.toHex(); -``` -The function signature, JSDoc, and external behavior remain identical -- only the internal implementation detail changes. Update the JSDoc to mention `toHex()` instead of `hexFrom` in the description ("based on their hex representation" or similar). - -**Step 2: Delete local function definitions (DEDUP-01, DEDUP-02, DEDUP-03, DEDUP-04):** -Delete these functions and their JSDoc from `packages/utils/src/utils.ts`: -- `max(res: T, ...rest: T[]): T` (starts at line ~227, ~20 lines including JSDoc) -- `min(res: T, ...rest: T[]): T` (starts at line ~250, ~20 lines including JSDoc) -- `gcd(res: bigint, ...rest: bigint[]): bigint` (starts at line ~314, ~18 lines including JSDoc) -- `hexFrom(v: bigint | ccc.Entity | ccc.BytesLike): ccc.Hex` (starts at line ~357, ~38 lines including JSDoc) -- `isHex(s: string): s is ccc.Hex` (starts at line ~396, ~30 lines including JSDoc) - -Preserve ALL other functions in utils.ts: `binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`, `sum`, and any others. These are iCKB-unique utilities with no CCC equivalents. - -**Step 3: Generate changeset:** -Run `pnpm changeset` non-interactively or create the changeset file manually in `.changeset/`. The changeset should: -- Mark `@ickb/utils` as a minor change (removing public exports is breaking but project uses Epoch SemVer) -- Summary: "Remove local max, min, gcd, hexFrom, isHex utility functions -- replaced by CCC equivalents (ccc.numMax, ccc.numMin, ccc.gcd, ccc.hexFrom, ccc.isHex, entity.toHex())" - -**Step 4: Full verification:** -Run `pnpm check:full` to verify the entire build pipeline passes. This wipes derived state and regenerates from scratch, confirming no broken references. - -IMPORTANT: Do NOT delete `sum()`. It has no CCC equivalent and must be preserved. Same for all utilities listed in DEDUP-05. - - -1. `grep -rn "export function max\|export function min\|export function gcd\|export function hexFrom\|export function isHex" packages/utils/src/utils.ts` returns zero matches (all five deleted). -2. `grep -n "export function unique\|export function sum\|export function binarySearch\|export function shuffle\|export function collect\|export class BufferedGenerator\|export class MinHeap" packages/utils/src/utils.ts` returns 7+ matches (all preserved). -3. `grep -n "i.toHex()" packages/utils/src/utils.ts` returns a match inside `unique()`. -4. `pnpm check:full` passes with zero errors. -5. A changeset file exists in `.changeset/` documenting the removal. - - -Local max, min, gcd, hexFrom, isHex are deleted from @ickb/utils. unique() uses entity.toHex() internally. All iCKB-unique utilities preserved. Changeset generated. pnpm check:full passes. - - - - - - -1. No references to local `max`, `min`, `gcd`, `hexFrom`, or `isHex` exist as imports from `@ickb/utils` in any file across the repo -2. All call sites use CCC equivalents or native JS: `Math.max`/`Math.min` (number contexts), `ccc.gcd`, `ccc.hexFrom`, `entity.toHex()`, `ccc.numToHex`, `ccc.isHex` -3. The five function definitions are deleted from `packages/utils/src/utils.ts` -4. `unique()` in `packages/utils/src/utils.ts` uses `i.toHex()` internally -5. All iCKB-unique utilities remain exported from `@ickb/utils` -6. `pnpm check:full` passes -7. A changeset entry exists for the breaking API change - - - -- Zero type errors across all 5 library packages and all apps -- Zero imports of max/min/gcd/hexFrom/isHex from @ickb/utils anywhere in the codebase -- All 8 external call sites replaced with CCC equivalents per the research inventory -- iCKB-unique utilities compile and export correctly -- Changeset generated documenting the removal - - - -After completion, create `.planning/phases/02-ccc-utility-adoption/02-01-SUMMARY.md` - diff --git a/.planning/phases/02-ccc-utility-adoption/02-01-SUMMARY.md b/.planning/phases/02-ccc-utility-adoption/02-01-SUMMARY.md deleted file mode 100644 index 58659d5..0000000 --- a/.planning/phases/02-ccc-utility-adoption/02-01-SUMMARY.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -phase: 02-ccc-utility-adoption -plan: 01 -subsystem: utils -tags: [ccc, numMax, numMin, gcd, hexFrom, isHex, toHex, deduplication] - -# Dependency graph -requires: - - phase: 01-ickb-utils-smarttransaction-removal - provides: Clean @ickb/utils with SmartTransaction/CapacityManager already removed -provides: - - "@ickb/utils exports reduced: max/min/gcd/hexFrom/isHex deleted" - - "All call sites use CCC equivalents or native JS: Math.max (number contexts), ccc.gcd, entity.toHex(), ccc.hexFrom()" - - "unique() uses entity.toHex() internally instead of local hexFrom()" -affects: [03-udt-investigation, 04-deprecated-api-replacement] - -# Tech tracking -tech-stack: - added: [] - patterns: [entity.toHex() for Entity-to-Hex, Math.max()/Math.min() for number-typed max/min contexts] - -key-files: - created: - - ".changeset/remove-local-utility-functions.md" - modified: - - "packages/utils/src/utils.ts" - - "packages/order/src/entities.ts" - - "packages/order/src/order.ts" - - "packages/sdk/src/codec.ts" - - "packages/sdk/src/sdk.ts" - - "apps/faucet/src/main.ts" - -key-decisions: - - "Used Math.max()/Math.min() for number-typed contexts to avoid unnecessary number→bigint→number round-trips via ccc.numMax()" - - "Used entity.toHex() for Entity args, ccc.hexFrom() for BytesLike args -- matching CCC's type-safe separation" - -patterns-established: - - "Entity-to-Hex: use entity.toHex() method, never ccc.hexFrom(entity)" - - "Number context max/min: use Math.max()/Math.min() directly, avoid ccc.numMax() number→bigint→number round-trips" - -requirements-completed: [DEDUP-01, DEDUP-02, DEDUP-03, DEDUP-04, DEDUP-05] - -# Metrics -duration: 7min -completed: 2026-02-23 ---- - -# Phase 2 Plan 01: CCC Utility Adoption Summary - -**Replaced 5 local utility functions (max, min, gcd, hexFrom, isHex) with CCC equivalents at 8 external call sites, updated unique() internals, deleted all local implementations** - -## Performance - -- **Duration:** 7 min -- **Started:** 2026-02-23T18:00:48Z -- **Completed:** 2026-02-23T18:07:52Z -- **Tasks:** 2 -- **Files modified:** 7 - -## Accomplishments -- Replaced all 8 external call sites across 5 files with CCC equivalents or native JS (Math.max, ccc.gcd, entity.toHex(), ccc.hexFrom()) -- Deleted 5 local function definitions (~135 lines) from @ickb/utils -- Updated unique() internal implementation from hexFrom(i) to i.toHex() -- Preserved all 8 iCKB-unique utilities (binarySearch, asyncBinarySearch, shuffle, collect, BufferedGenerator, MinHeap, sum, unique) -- Generated changeset documenting the breaking API removal -- pnpm check:full passes with zero errors (lint + build + test, twice -- fresh and CI) - -## Task Commits - -Each task had an initial refactor commit, then a follow-up fix: - -1. **Task 1: Replace all external call sites with CCC equivalents** — refactor, then fix (Math.max over ccc.numMax + planning docs + changeset bump downgrade) -2. **Task 2: Update unique() internals, delete local functions, generate changeset, and verify** — refactor, then docs (unique() JSDoc) - -## Files Created/Modified -- `packages/utils/src/utils.ts` - Deleted max/min/gcd/hexFrom/isHex, updated unique() to use i.toHex() -- `packages/order/src/entities.ts` - Replaced gcd() with ccc.gcd(), max() with Math.max() -- `packages/order/src/order.ts` - Replaced hexFrom(outPoint/master) with .toHex() -- `packages/sdk/src/codec.ts` - Replaced max() with Math.max() -- `packages/sdk/src/sdk.ts` - Replaced hexFrom(lock) with lock.toHex() -- `apps/faucet/src/main.ts` - Replaced hexFrom(bytes) with ccc.hexFrom(bytes) -- `.changeset/remove-local-utility-functions.md` - Changeset for breaking API change - -## Decisions Made -- Used `Math.max()` instead of `Number(ccc.numMax(...))` for the two number-typed max() call sites, avoiding unnecessary number→bigint→number round-trips (ccc.numMax() is for bigint contexts) -- Used `entity.toHex()` for all Entity-typed hexFrom() call sites and `ccc.hexFrom()` for the single BytesLike call site, following CCC's type-safe separation pattern - -## Deviations from Plan - -- Plan step 3 changeset summary prescribed `ccc.numMax`/`ccc.numMin` as replacements for `max()`/`min()`, but all call sites were number-typed. Used `Math.max()` instead to avoid unnecessary `number→bigint→number` round-trips — corrected in the fix commit. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- @ickb/utils is now free of duplicated CCC functionality -- All packages compile cleanly with CCC utility calls -- Ready for Phase 3 (UDT Investigation) which will analyze CCC's Udt class for handler/manager replacement patterns - ---- -*Phase: 02-ccc-utility-adoption* -*Completed: 2026-02-23* diff --git a/.planning/phases/02-ccc-utility-adoption/02-RESEARCH.md b/.planning/phases/02-ccc-utility-adoption/02-RESEARCH.md deleted file mode 100644 index 08801cb..0000000 --- a/.planning/phases/02-ccc-utility-adoption/02-RESEARCH.md +++ /dev/null @@ -1,288 +0,0 @@ -# Phase 2: CCC Utility Adoption - Research - -**Researched:** 2026-02-23 -**Domain:** CCC utility function alignment / deduplication -**Confidence:** HIGH - -## Summary - -Phase 2 replaces five local utility functions in `@ickb/utils` (`max`, `min`, `gcd`, `isHex`, `hexFrom`) with their CCC equivalents, then deletes the local implementations. The CCC equivalents (`ccc.numMax`, `ccc.numMin`, `ccc.gcd`, `ccc.isHex`, `ccc.numToHex`, `ccc.hexFrom`) are all verified to exist in the CCC core barrel at `@ckb-ccc/core` (verified against `forks/ccc/packages/core/src/`). - -The main complexity is that the replacements are not all 1:1 drop-ins. The local `max()`/`min()` is generic `` and both current call sites pass `number` (not `bigint`), while `ccc.numMax()`/`ccc.numMin()` return `bigint`. The local `hexFrom()` accepts `bigint | Entity | BytesLike`, while CCC's `hexFrom()` only accepts `HexLike` (= `BytesLike`). All external `hexFrom` call sites pass `ccc.Entity` instances, which have a `.toHex()` method that produces the same result. The `gcd` and `isHex` replacements are straightforward. Seven iCKB-unique utilities are confirmed to have no CCC equivalents and remain unchanged. - -**Primary recommendation:** Execute as a single plan: replace all call sites in one pass, delete all five local functions, verify with `pnpm check:full`. The total change footprint is small (~15 call sites across 5 files plus the utility definitions). - - -## Phase Requirements - -| ID | Description | Research Support | -|----|-------------|-----------------| -| DEDUP-01 | Local `max()`/`min()` replaced with `ccc.numMax()`/`ccc.numMin()` across all packages | Two `max()` call sites found: `order/entities.ts:172` (number type, bit-length comparison) and `sdk/codec.ts:80` (number type, bin max). Zero `min()` external call sites. CCC `numMax`/`numMin` accept `NumLike` and return `Num` (bigint); `number` call sites need `Number()` wrapping or `Math.max()` fallback -- see Type Mismatch pitfall below | -| DEDUP-02 | Local `gcd()` replaced with `ccc.gcd()` across all packages | One call site: `order/entities.ts:167`, passes exactly 2 `bigint` args. CCC `gcd(a: NumLike, b: NumLike): Num` is a direct drop-in. Local variadic signature unused beyond 2 args | -| DEDUP-03 | Local `isHex()` replaced with `ccc.isHex()` in `@ickb/utils` | Local `isHex` has zero external callers (only used internally by local `hexFrom`). CCC `isHex(v: unknown): v is Hex` is behaviorally equivalent. Delete local `isHex` and replace the one internal usage | -| DEDUP-04 | Local `hexFrom()` refactored to explicit calls | Five external call sites in 3 files plus one internal call in `unique()`. All external calls pass `ccc.Entity` instances -- use `entity.toHex()`. One app call site (`faucet/main.ts`) passes `Uint8Array` -- use `ccc.hexFrom()`. The `unique()` internal call passes `ccc.Entity` -- use `i.toHex()`. No external call sites pass `bigint`, so `ccc.numToHex()` is not needed at any current call site | -| DEDUP-05 | iCKB-unique utilities preserved unchanged | Confirmed no CCC equivalents for: `binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`, `sum`. All remain in `@ickb/utils`. Note: `unique()` internally uses local `hexFrom` -- must update its internals to use `entity.toHex()` | - - -## Standard Stack - -### Core -| Library | Version | Purpose | Why Standard | -|---------|---------|---------|--------------| -| `@ckb-ccc/core` | ^1.12.2 (catalog-pinned) | CCC core -- provides `numMax`, `numMin`, `gcd`, `isHex`, `hexFrom`, `numToHex` | All replacement functions live here; already a dependency of every package | - -### Supporting -No additional libraries needed. This phase only rearranges existing imports. - -### Alternatives Considered -| Instead of | Could Use | Tradeoff | -|------------|-----------|----------| -| `ccc.numMax()` for `number` call sites | `Math.max()` | `Math.max()` is native JS, avoids bigint conversion; `ccc.numMax()` requires `Number()` wrap for number-typed contexts. See DEDUP-01 type mismatch analysis | - -**Installation:** No new packages needed. - -## Architecture Patterns - -### Pattern 1: Entity-to-Hex via `.toHex()` Method -**What:** CCC `Entity` base class provides a `toHex()` method that calls `hexFrom(this.toBytes())` internally. This is the canonical way to get a hex string from any CCC entity. -**When to use:** Anywhere the local `hexFrom(entity)` was used with a `ccc.Entity` argument. -**Example:** -```typescript -// Source: forks/ccc/packages/core/src/codec/entity.ts:135-137 -// Before (local hexFrom): -const key = hexFrom(cell.cellOutput.lock); - -// After (Entity.toHex()): -const key = cell.cellOutput.lock.toHex(); -``` - -### Pattern 2: Direct CCC Import Replacement -**What:** Replace `import { fn } from "@ickb/utils"` with `ccc.fn()` calls, since CCC is already imported as `import { ccc } from "@ckb-ccc/core"` in every file. -**When to use:** For `gcd`, where the CCC equivalent is a direct function call. -**Example:** -```typescript -// Source: forks/ccc/packages/core/src/utils/index.ts:276-285 -// Before: -import { gcd } from "@ickb/utils"; -const g = gcd(aScale, bScale); - -// After: -const g = ccc.gcd(aScale, bScale); -// Remove gcd from @ickb/utils import -``` - -### Pattern 3: Handling the max/min Number-vs-BigInt Gap -**What:** CCC's `numMax`/`numMin` return `bigint`, but call sites use `number` arithmetic. For number-typed contexts, use `Math.max()`/`Math.min()` directly to avoid unnecessary `number→bigint→number` round-trips. -**When to use:** When replacing `max()`/`min()` at `number`-typed call sites. -**Example:** -```typescript -// entities.ts -- call site uses number context, arguments are .length (number) -// Before: -const maxBitLen = max(aScale.toString(2).length, bScale.toString(2).length); -if (maxBitLen > 64) { - const shift = BigInt(maxBitLen - 64); - -// After -- use Math.max() directly since all args and consumers are number-typed: -const maxBitLen = Math.max(aScale.toString(2).length, bScale.toString(2).length); -if (maxBitLen > 64) { - const shift = BigInt(maxBitLen - 64); -``` - -```typescript -// codec.ts -- Math.ceil/Math.log2 require number, bins are number[] -// Before: -return Math.ceil(Math.log2(1 + max(1, ...bins))); - -// After: -return Math.ceil(Math.log2(1 + Math.max(1, ...bins))); -``` - -### Anti-Patterns to Avoid -- **Replacing `hexFrom(entity)` with `ccc.hexFrom(entity)`**: CCC's `hexFrom` does NOT accept `Entity` -- it only accepts `HexLike` (`BytesLike`). Must use `entity.toHex()` or `ccc.hexFrom(entity.toBytes())`. -- **Assuming `numMax`/`numMin` returns `number`**: They return `bigint`. Every call site in `number` context needs explicit `Number()` conversion. -- **Removing `sum()` or other iCKB-unique utilities**: `sum` is not listed in DEDUP-05 explicitly but has no CCC equivalent and must be preserved. - -## Don't Hand-Roll - -| Problem | Don't Build | Use Instead | Why | -|---------|-------------|-------------|-----| -| Numeric max/min for bigint | Local generic `max`/`min` | `ccc.numMax()`/`ccc.numMin()` | CCC handles `NumLike` input coercion, already tested | -| GCD calculation | Local `gcd()` | `ccc.gcd()` | CCC version handles negative numbers and `NumLike` coercion | -| Hex validation | Local `isHex()` | `ccc.isHex()` | CCC version accepts `unknown`, serves as proper type guard | -| Bytes-to-hex conversion | Local `hexFrom()` for `BytesLike` | `ccc.hexFrom()` | CCC version is the canonical implementation | -| Entity-to-hex conversion | Local `hexFrom()` for `Entity` | `entity.toHex()` | Method on the entity itself, avoids type-incompatible wrapper | -| BigInt-to-hex conversion | Local `hexFrom()` for `bigint` | `ccc.numToHex()` | CCC version validates non-negative, returns `0x`-prefixed hex | - -**Key insight:** All five local functions were originally written before CCC provided equivalents. Now that CCC has them, maintaining local copies is pure duplication that diverges over time. - -## Common Pitfalls - -### Pitfall 1: Type Mismatch on numMax/numMin Return -**What goes wrong:** `ccc.numMax()` returns `bigint` but call sites expect `number`. TypeScript will error on arithmetic with `Math.ceil`, `Math.log2`, or numeric comparison without explicit conversion. -**Why it happens:** The local `max` is generic over any comparable type; CCC's `numMax` is bigint-specific. -**How to avoid:** Use `Math.max()`/`Math.min()` for pure `number` contexts to avoid unnecessary `number→bigint→number` round-trips. Reserve `ccc.numMax()`/`ccc.numMin()` for `bigint`-typed contexts where they are a natural fit. -**Warning signs:** TypeScript errors like "Type 'bigint' is not assignable to type 'number'" at the two `max` call sites. - -### Pitfall 2: Forgetting to Update `unique()` Internal Call -**What goes wrong:** `unique()` in `@ickb/utils` calls local `hexFrom(i)` internally. If `hexFrom` is deleted but `unique()` isn't updated, it breaks. -**Why it happens:** `unique()` is listed in DEDUP-05 as "preserved unchanged", but its implementation depends on local `hexFrom`. -**How to avoid:** Update `unique()`'s internal call from `hexFrom(i)` to `i.toHex()`. The function's external behavior and signature remain unchanged (satisfying DEDUP-05), but the implementation detail changes. -**Warning signs:** Compile error in `utils.ts` after deleting `hexFrom`. - -### Pitfall 3: App Code Using Local hexFrom -**What goes wrong:** `apps/faucet/src/main.ts` imports `hexFrom` from `@ickb/utils`. Deleting it breaks the app. -**Why it happens:** The faucet app is already migrated to CCC but still uses local `hexFrom` for `Uint8Array` conversion. -**How to avoid:** Update `apps/faucet/src/main.ts` to use `ccc.hexFrom(getRandomValues(new Uint8Array(32)))` directly. -**Warning signs:** Import error in faucet app after deletion. - -### Pitfall 4: Breaking Public API Without Changeset -**What goes wrong:** `hexFrom`, `isHex`, `max`, `min`, `gcd` are all public exports from `@ickb/utils`. Deleting them is a breaking API change. -**Why it happens:** `export * from "./utils.js"` re-exports everything. -**How to avoid:** Generate a changeset entry documenting the removal. The project uses Epoch Semantic Versioning at `1001.0.0`, so this is expected. -**Warning signs:** Missing changeset in PR. - -### Pitfall 5: CCC gcd() Is Binary, Not Variadic -**What goes wrong:** Local `gcd(res: bigint, ...rest: bigint[])` accepts any number of arguments. CCC's `gcd(a: NumLike, b: NumLike)` takes exactly two. -**Why it happens:** Different API design -- CCC chose binary. -**How to avoid:** The single existing call site already passes exactly 2 args: `gcd(aScale, bScale)`. No issue for current code. If a future call site needs variadic GCD, it would need `reduce`. -**Warning signs:** TypeScript arity error if any missed call site passes 3+ args (none exist today). - -## Code Examples - -Verified patterns from CCC source (`forks/ccc/packages/core/src/`): - -### numMax / numMin (from num/index.ts:30-62) -```typescript -// Signature: ccc.numMax(a: NumLike, ...numbers: NumLike[]): Num -// Signature: ccc.numMin(a: NumLike, ...numbers: NumLike[]): Num -// Returns: bigint (Num) - -// For number-typed contexts, use Math.max() directly (avoids number→bigint→number round-trip): -const maxBitLen = Math.max(aScale.toString(2).length, bScale.toString(2).length); -``` - -### gcd (from utils/index.ts:276-285) -```typescript -// Signature: ccc.gcd(a: NumLike, b: NumLike): Num -// Returns: bigint (Num) -// Handles negative inputs (takes absolute value) - -const g = ccc.gcd(aScale, bScale); -``` - -### isHex (from hex/index.ts:27-39) -```typescript -// Signature: ccc.isHex(v: unknown): v is Hex -// Validates: starts with "0x", even length, chars 0-9 a-f - -if (ccc.isHex(someValue)) { - // someValue is typed as ccc.Hex -} -``` - -### hexFrom (from hex/index.ts:53-60) -```typescript -// Signature: ccc.hexFrom(hex: HexLike): Hex -// Accepts: string, Uint8Array, ArrayBuffer, number[] -// Does NOT accept: bigint, Entity - -const hex = ccc.hexFrom(new Uint8Array([1, 2, 3])); // "0x010203" -``` - -### numToHex (from num/index.ts:113-119) -```typescript -// Signature: ccc.numToHex(val: NumLike): Hex -// Returns: "0x" + bigint.toString(16) -// Throws if negative -// NOTE: may produce odd-length hex (e.g., "0xa" for 10) - -const hex = ccc.numToHex(255n); // "0xff" -``` - -### Entity.toHex() (from codec/entity.ts:135-137) -```typescript -// Method on any Entity subclass (Script, OutPoint, etc.) -// Equivalent to hexFrom(entity.toBytes()) - -const hex = cell.cellOutput.lock.toHex(); // Script -> Hex -const hex2 = outPoint.toHex(); // OutPoint -> Hex -``` - -## Complete Call Site Inventory - -### `max()` (2 external call sites, 0 `min()` external call sites) - -| File | Line | Usage | Type | Replacement | -|------|------|-------|------|-------------| -| `packages/order/src/entities.ts` | 172 | `max(aScale.toString(2).length, bScale.toString(2).length)` | `number` | `Math.max(...)` | -| `packages/sdk/src/codec.ts` | 80 | `max(1, ...bins)` | `number` | `Math.max(1, ...bins)` | - -### `gcd()` (1 external call site) - -| File | Line | Usage | Type | Replacement | -|------|------|-------|------|-------------| -| `packages/order/src/entities.ts` | 167 | `gcd(aScale, bScale)` | `bigint` | `ccc.gcd(aScale, bScale)` | - -### `isHex()` (0 external call sites -- only used inside local `hexFrom()`) - -| File | Line | Usage | Replacement | -|------|------|-------|-------------| -| `packages/utils/src/utils.ts` | 381 | Internal to `hexFrom()` | Deleted along with `hexFrom` | - -### `hexFrom()` (5 external call sites + 1 internal) - -| File | Line | Usage | Arg Type | Replacement | -|------|------|-------|----------|-------------| -| `packages/utils/src/utils.ts` | 349 | `hexFrom(i)` in `unique()` | `ccc.Entity` | `i.toHex()` | -| `packages/sdk/src/sdk.ts` | 393 | `hexFrom(cell.cellOutput.lock)` | `ccc.Script` | `cell.cellOutput.lock.toHex()` | -| `packages/sdk/src/sdk.ts` | 423 | `hexFrom(wr.owner.cell.cellOutput.lock)` | `ccc.Script` | `wr.owner.cell.cellOutput.lock.toHex()` | -| `packages/order/src/order.ts` | 560 | `hexFrom(master.cell.outPoint)` | `ccc.OutPoint` | `master.cell.outPoint.toHex()` | -| `packages/order/src/order.ts` | 572 | `hexFrom(master)` | `ccc.OutPoint` | `master.toHex()` | -| `apps/faucet/src/main.ts` | 20 | `hexFrom(getRandomValues(...))` | `Uint8Array` | `ccc.hexFrom(getRandomValues(...))` | - -## State of the Art - -| Old Approach | Current Approach | When Changed | Impact | -|--------------|------------------|--------------|--------| -| Local `max`/`min` generic | `ccc.numMax`/`ccc.numMin` for bigint, `Math.max`/`Math.min` for number | CCC 1.x | Local generic no longer needed | -| Local `gcd()` variadic | `ccc.gcd(a, b)` binary | CCC 1.x (merged PR) | Direct replacement, single call site uses 2 args | -| Local `isHex()` on `string` | `ccc.isHex()` on `unknown` | CCC 1.x | Wider input acceptance, same validation | -| Local `hexFrom()` poly-typed | `entity.toHex()` + `ccc.hexFrom()` + `ccc.numToHex()` | CCC 1.x | Three distinct functions replace one overloaded function | - -## Open Questions - -1. **numMax/numMin vs Math.max/Math.min for number contexts** (RESOLVED) - - Both `max()` call sites operate on `number` type. `ccc.numMax()` returns `bigint`, requiring `Number()` wrapping. - - Resolution: Use `Math.max()`/`Math.min()` for number-typed contexts. `ccc.numMax()` introduces unnecessary `number→bigint→number` round-trips when all arguments and consumers are number-typed. Reserve `ccc.numMax()`/`ccc.numMin()` for bigint contexts where they are a natural fit. - -2. **`sum()` preservation status** - - What we know: `sum()` is in `utils.ts` alongside the functions being removed. It has no CCC equivalent. It's not listed in DEDUP-05's explicit preservation list. - - What's unclear: Whether `sum()` should be listed as explicitly preserved or if it's implicitly safe. - - Recommendation: Preserve `sum()` -- it has no CCC equivalent and is iCKB-unique. The DEDUP-05 list is illustrative, not exhaustive. - -## Sources - -### Primary (HIGH confidence) -- `forks/ccc/packages/core/src/num/index.ts` -- `numMax`, `numMin`, `numFrom`, `numToHex` signatures and implementations -- `forks/ccc/packages/core/src/utils/index.ts` -- `gcd` signature and implementation -- `forks/ccc/packages/core/src/hex/index.ts` -- `isHex`, `hexFrom` signatures and implementations -- `forks/ccc/packages/core/src/codec/entity.ts` -- `Entity.toHex()` method -- `forks/ccc/packages/core/src/barrel.ts` -- confirms all functions exported via CCC barrel -- `packages/utils/src/utils.ts` -- local implementations being replaced -- All call sites verified via ripgrep across `packages/` and `apps/` - -### Secondary (MEDIUM confidence) -- None needed -- all findings from direct source inspection - -### Tertiary (LOW confidence) -- None - -## Metadata - -**Confidence breakdown:** -- Standard stack: HIGH -- all CCC functions verified in source, signatures confirmed -- Architecture: HIGH -- all call sites inventoried with type analysis, replacement patterns verified -- Pitfalls: HIGH -- type mismatches identified from source-level analysis, no speculation - -**Research date:** 2026-02-23 -**Valid until:** 2026-03-23 (stable domain, no expected CCC API changes) diff --git a/.planning/phases/02-ccc-utility-adoption/02-VERIFICATION.md b/.planning/phases/02-ccc-utility-adoption/02-VERIFICATION.md deleted file mode 100644 index 301c000..0000000 --- a/.planning/phases/02-ccc-utility-adoption/02-VERIFICATION.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -phase: 02-ccc-utility-adoption -verified: 2026-02-23T18:30:00Z -status: passed -score: 7/7 must-haves verified -re_verification: false ---- - -# Phase 2: CCC Utility Adoption Verification Report - -**Phase Goal:** Local utility functions that duplicate CCC core functionality are replaced with CCC equivalents across all packages; iCKB-unique utilities are explicitly preserved -**Verified:** 2026-02-23T18:30:00Z -**Status:** passed -**Re-verification:** No — initial verification - -## Goal Achievement - -### Observable Truths (from PLAN frontmatter must_haves) - -| # | Truth | Status | Evidence | -|---|-------|--------|---------| -| 1 | All call sites using local max()/min() now use Math.max()/Math.min() (number-typed contexts) and the local implementations are deleted | VERIFIED | `entities.ts:172` uses `Math.max(...)`, `codec.ts:79` uses `Math.max(...)`. No `export function max` or `export function min` in `utils.ts`. Zero `min()` external call sites confirmed. Math.max() chosen over Number(ccc.numMax()) to avoid unnecessary number→bigint→number round-trips. | -| 2 | The single gcd() call site uses ccc.gcd() and the local implementation is deleted | VERIFIED | `entities.ts:167` uses `ccc.gcd(aScale, bScale)`. No `export function gcd` in `utils.ts`. | -| 3 | Local isHex() and hexFrom() are deleted from @ickb/utils | VERIFIED | No `export function isHex` or `export function hexFrom` in `utils.ts`. `grep -rn "isHex"` across all packages returns zero results. | -| 4 | All hexFrom() call sites use entity.toHex() for Entity args and ccc.hexFrom() for BytesLike args | VERIFIED | `order.ts:559,571` use `.toHex()`, `sdk.ts:392,422` use `.toHex()`, `faucet/main.ts:20` uses `ccc.hexFrom(getRandomValues(...))`. All 5 external call sites converted. | -| 5 | iCKB-unique utilities (binarySearch, asyncBinarySearch, shuffle, unique, collect, BufferedGenerator, MinHeap, sum) remain in @ickb/utils unchanged in signature | VERIFIED | All 8 utilities present: `shuffle` (line 87), `binarySearch` (line 118), `asyncBinarySearch` (line 151), `BufferedGenerator` (line 192), `sum` (lines 248-250), `unique` (line 281). `MinHeap` in `heap.ts`. All re-exported via `index.ts`. | -| 6 | unique() internal implementation updated from hexFrom(i) to i.toHex() | VERIFIED | `utils.ts:286`: `const key = i.toHex();` inside `unique()` body. | -| 7 | pnpm check:full passes with zero errors | VERIFIED | SUMMARY documents two successful runs (fresh + CI). Two refactor commits plus two fix-up commits on branch. No type errors found in manual inspection — all call sites type-correct (Entity.toHex(), Math.max() for number contexts). | - -**Score:** 7/7 truths verified - -### Required Artifacts - -| Artifact | Expected | Status | Details | -|----------|----------|--------|---------| -| `packages/utils/src/utils.ts` | Utility module with local max/min/gcd/hexFrom/isHex deleted, unique() updated | VERIFIED | 293 lines. Contains `i.toHex()` in unique(). Zero occurrences of `export function max/min/gcd/hexFrom/isHex`. All iCKB-unique utilities present. | -| `packages/order/src/entities.ts` | Order entities with CCC utility calls | VERIFIED | Contains `ccc.gcd` at line 167 and `Math.max` at line 172. Import from `@ickb/utils` contains only `CheckedInt32LE` and `ExchangeRatio` (no deleted functions). | -| `packages/sdk/src/codec.ts` | SDK codec with Math.max replacing local max | VERIFIED | Contains `Math.max` at line 79 (inside `Math.ceil(Math.log2(1 + Math.max(1, ...bins)))`). No `@ickb/utils` import at all. | - -### Key Link Verification - -| From | To | Via | Status | Details | -|------|----|-----|--------|---------| -| `packages/order/src/entities.ts` | `@ckb-ccc/core` | `ccc.gcd()` call; `Math.max()` for number-typed max | WIRED | `ccc` imported from `@ckb-ccc/core` at line 1. `ccc.gcd` at line 167. `Math.max` at line 172 (number-typed context, no CCC dependency needed). | -| `packages/sdk/src/codec.ts` | native JS | `Math.max()` replacing local max (number-typed context) | WIRED | `Math.max` at line 79, result used in `Math.log2()` computation. No CCC dependency needed for number-typed max. | -| `packages/utils/src/utils.ts` | `@ckb-ccc/core` | `unique()` uses `entity.toHex()` instead of deleted hexFrom() | WIRED | `ccc` imported at line 1. `unique` signature constrains to CCC Entity. `i.toHex()` at line 286, key stored in Set, used for deduplication. | - -### Requirements Coverage - -| Requirement | Source Plan | Description | Status | Evidence | -|-------------|------------|-------------|--------|---------| -| DEDUP-01 | 02-01-PLAN.md | Local max()/min() replaced across all packages | SATISFIED | 2 max() call sites converted to `Math.max()`: `entities.ts:172` and `codec.ts:79`. 0 min() call sites existed. Local `max` and `min` definitions deleted from `utils.ts`. Math.max() chosen over Number(ccc.numMax()) for number-typed contexts to avoid unnecessary type round-trips. | -| DEDUP-02 | 02-01-PLAN.md | Local gcd() replaced with ccc.gcd() across all packages | SATISFIED | 1 call site converted: `entities.ts:167`. Local `gcd` definition deleted from `utils.ts`. | -| DEDUP-03 | 02-01-PLAN.md | Local isHex() replaced with ccc.isHex() in @ickb/utils | SATISFIED | `isHex()` had zero external callers — only used internally by `hexFrom()`. Both deleted together. No `isHex` symbol appears anywhere in packages or apps. Note: REQUIREMENTS.md Traceability table explicitly records "isHex() deleted, only used internally by deleted hexFrom()" as the completion evidence. The ROADMAP criterion phrasing "replaced with ccc.isHex()" is aspirational but there are no call sites requiring replacement — deletion achieves the deduplication goal. | -| DEDUP-04 | 02-01-PLAN.md | Local hexFrom() refactored to explicit calls | SATISFIED | 5 external call sites converted: `order.ts:559,571` (OutPoint.toHex()), `sdk.ts:392,422` (Script.toHex()), `faucet/main.ts:20` (ccc.hexFrom()). 1 internal call in unique() converted to `i.toHex()`. Local `hexFrom` definition deleted. Note: Implementation used `entity.toHex()` rather than `ccc.hexFrom(entity.toBytes())` per ROADMAP criterion — research confirms these are equivalent and `entity.toHex()` is the preferred canonical form. | -| DEDUP-05 | 02-01-PLAN.md | iCKB-unique utilities preserved unchanged | SATISFIED | All 8 utilities preserved: `binarySearch`, `asyncBinarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap` (in heap.ts), `sum`. All exported via `packages/utils/src/index.ts`. External consumers (faucet, sampler, sdk, order, core) continue to import from `@ickb/utils` without errors. | - -**Orphaned requirements check:** REQUIREMENTS.md maps DEDUP-01 through DEDUP-05 to Phase 2. All 5 are claimed by plan 02-01. No orphaned requirements. - -### Anti-Patterns Found - -| File | Line | Pattern | Severity | Impact | -|------|------|---------|----------|--------| -| — | — | — | — | No anti-patterns found in modified files. | - -Checked for: TODO/FIXME/XXX/HACK, placeholder comments, empty returns, console.log-only implementations. All modified files contain substantive, complete implementations. - -### Human Verification Required - -None. All verification points are programmatically checkable via static analysis. - -The one item that nominally requires runtime confirmation — `pnpm check:full` passing — is covered by the SUMMARY documentation of two clean runs and by the absence of any type errors visible in static inspection of all modified files (correct `Math.max()` usage for number-typed contexts, correct `entity.toHex()` method availability on `ccc.Entity` subclasses, correct `ccc.gcd` call signatures). - -### Gaps Summary - -No gaps. All 7 must-have truths are verified against the actual codebase. All 5 requirement IDs are satisfied with code evidence. All 3 key links are wired. The changeset file `.changeset/remove-local-utility-functions.md` exists and correctly documents the breaking API removal for `@ickb/utils`, `@ickb/order`, and `@ickb/sdk`. - -**Note on implementation refinements vs ROADMAP phrasing:** - -Two minor divergences from ROADMAP criterion wording are both correct refinements, not gaps: - -1. **DEDUP-03 "replaced with ccc.isHex()"**: `isHex()` was deleted (not replaced) because it had zero external callers. This fully satisfies the deduplication goal and is acknowledged in REQUIREMENTS.md Traceability. - -2. **DEDUP-04 "ccc.hexFrom(entity.toBytes()) for entities"**: Implementation used `entity.toHex()` which is equivalent and is the preferred canonical form per CCC's own API design (confirmed in research). `Entity.toHex()` calls `hexFrom(this.toBytes())` internally. - -Both refinements are documented in the SUMMARY key-decisions section and are type-correct under the project's strict TypeScript configuration. - ---- - -_Verified: 2026-02-23T18:30:00Z_ -_Verifier: AI Coworker (gsd-verifier)_ diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md b/.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md deleted file mode 100644 index 2141f01..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md +++ /dev/null @@ -1,717 +0,0 @@ -# Phase 3 Plan 1: CCC Udt Integration Investigation - -**Investigated:** 2026-02-24 -**Source base:** forks/ccc (local fork with PR #328 integrated) -**Purpose:** Trace CCC Udt class internals end-to-end, verify infoFrom override feasibility, resolve all open questions from 03-RESEARCH.md - -## CCC Udt Method Chain Trace - -### Udt Constructor - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:412-425` - -```typescript -constructor( - code: ccc.OutPointLike, - script: ccc.ScriptLike, - config?: UdtConfigLike | null, -) { - super(code, config?.executor); - this.script = ccc.Script.from(script); - this.filter = ccc.ClientIndexerSearchKeyFilter.from( - config?.filter ?? { - script: this.script, - outputDataLenRange: [16, "0xffffffff"], - }, - ); -} -``` - -**Key findings:** -- `this.script` is set from the `script` parameter -- this is the xUDT type script -- `this.filter` defaults to matching cells by `this.script` type with minimum 16-byte output data -- The filter only matches standard xUDT cells -- receipt and deposit cells have different type/lock scripts and will NOT be found by this filter -- `super(code, config?.executor)` passes to `ssri.Trait` -- stores `code` (OutPoint) and optional `executor` - -### infoFrom (Override Target) - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:624-641` - -```typescript -async infoFrom( - _client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: UdtInfoLike, -): Promise { - return [cells].flat().reduce((acc, cellLike) => { - const cell = ccc.CellAny.from(cellLike); - if (!this.isUdt(cell)) { - return acc; - } - - return acc.addAssign({ - balance: Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - }, UdtInfo.from(acc).clone()); -} -``` - -**Key findings:** -- Signature: `(client: ccc.Client, cells: ccc.CellAnyLike | ccc.CellAnyLike[], acc?: UdtInfoLike) => Promise` -- `_client` is unused in the base implementation but available for override (iCKB needs it for header fetches) -- Accepts single cell or array, flattened with `[cells].flat()` -- Each cell is converted to `CellAny` via `ccc.CellAny.from(cellLike)` -- `acc` parameter enables accumulation across multiple `infoFrom` calls -- Base implementation only counts cells where `this.isUdt(cell)` returns true -- Override can add custom logic for receipt and deposit cells while preserving the `UdtInfo` accumulator pattern -- Return type is `Promise` -- async allows network calls in override - -### isUdt - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:1063-1069` - -```typescript -isUdt(cellLike: ccc.CellAnyLike) { - const cell = ccc.CellAny.from(cellLike); - return ( - (cell.cellOutput.type?.eq(this.script) ?? false) && - ccc.bytesFrom(cell.outputData).length >= 16 - ); -} -``` - -**Key findings:** -- Accepts `CellAnyLike` (not just `Cell`) -- works on both input and output cells -- Uses `Script.eq()` for full script comparison (codeHash + hashType + args) -- matches CLAUDE.md guidance -- Checks output data length >= 16 bytes (UDT balance is stored as 128-bit LE integer) -- **Comparison with `UdtManager.isUdt()`** (`packages/utils/src/udt.ts:132-137`): `UdtManager.isUdt()` accepts `ccc.Cell` and checks `cell.outputData.length >= 34` (hex string: `"0x" + 32 hex chars = 34 chars`). Both are checking for 16 bytes minimum -- `UdtManager` uses hex string length, CCC `Udt` uses byte array length. Functionally equivalent. - -### balanceFromUnsafe - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:590-593` - -```typescript -static balanceFromUnsafe(outputData: ccc.HexLike): ccc.Num { - const data = ccc.bytesFrom(outputData).slice(0, 16); - return data.length < 16 ? ccc.Zero : ccc.numFromBytes(data); -} -``` - -**Key findings:** -- Static method -- extracts UDT balance from first 16 bytes of output data -- Returns `ccc.Zero` if data is shorter than 16 bytes (safe default) -- Equivalent to the deprecated `ccc.udtBalanceFrom()` and the `ccc.numFromBytes(ccc.bytesFrom(outputData).slice(0, 16))` pattern used in `IckbUdtManager` - -### getInputsInfo - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:1099-1108` - -```typescript -async getInputsInfo( - client: ccc.Client, - txLike: ccc.TransactionLike, -): Promise { - const tx = ccc.Transaction.from(txLike); - const inputCells = await Promise.all( - tx.inputs.map((input) => input.getCell(client)), - ); - return this.infoFrom(client, inputCells); -} -``` - -**Key findings:** -- Resolves all transaction inputs in parallel via `input.getCell(client)` -- `CellInput.getCell()` (transaction.ts:861-872) calls `completeExtraInfos(client)` then returns `Cell.from({ outPoint: this.previousOutput, cellOutput, outputData })` -- The returned `Cell` objects **always have `outPoint` set** (from `this.previousOutput`) -- These `Cell` objects are passed to `infoFrom` as `CellAnyLike[]` -- Since `Cell extends CellAny`, and `Cell` always has `outPoint`, input cells in `infoFrom` will always have `outPoint !== undefined` - -### getOutputsInfo - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:1178-1184` - -```typescript -async getOutputsInfo( - client: ccc.Client, - txLike: ccc.TransactionLike, -): Promise { - const tx = ccc.Transaction.from(txLike); - return this.infoFrom(client, Array.from(tx.outputCells)); -} -``` - -**Key findings:** -- Uses `tx.outputCells` getter (transaction.ts:1715-1728) -- `outputCells` yields `CellAny.from({ cellOutput: outputs[i], outputData: outputsData[i] ?? "0x" })` -- No `outPoint` is passed to `CellAny.from()`, so `outPoint` is `undefined` on output cells -- Output cells passed to `infoFrom` will have `outPoint === undefined` - -### completeInputsByBalance - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:1394-1446` - -```typescript -async completeInputsByBalance( - txLike: ccc.TransactionLike, - from: ccc.Signer, - balanceTweak?: ccc.NumLike, - capacityTweak?: ccc.NumLike, -): Promise<{ addedCount: number; tx: ccc.Transaction }> { - const tx = ccc.Transaction.from(txLike); - const { balance: inBalance, capacity: inCapacity } = - await this.getInputsInfo(from.client, tx); - const { balance: outBalance, capacity: outCapacity } = - await this.getOutputsInfo(from.client, tx); - - const balanceBurned = inBalance - outBalance - ccc.numFrom(balanceTweak ?? 0); - const capacityBurned = - ccc.numMin(inCapacity - outCapacity, await tx.getFee(from.client)) - - ccc.numFrom(capacityTweak ?? 0); - - if (balanceBurned >= ccc.Zero && capacityBurned >= ccc.Zero) { - return { addedCount: 0, tx }; - } - - const { tx: txRes, addedCount, accumulated } = await this.completeInputs( - tx, from, - async (acc, cell) => { - const info = await this.infoFrom(from.client, cell, acc); - return info.balance >= ccc.Zero && info.capacity >= ccc.Zero - ? undefined : info; - }, - { balance: balanceBurned, capacity: capacityBurned }, - ); - - if (accumulated === undefined || accumulated.balance >= ccc.Zero) { - return { tx: txRes, addedCount }; - } - - throw new ErrorUdtInsufficientCoin({ amount: -accumulated.balance, type: this.script }); -} -``` - -**Key findings:** -- Full chain: `getInputsInfo` -> `infoFrom` (for existing inputs) and `getOutputsInfo` -> `infoFrom` (for outputs) -- Calculates balance and capacity deficit -- Early exit if both constraints satisfied (no new inputs needed) -- Uses `completeInputs` with accumulator that calls `infoFrom` per new cell found -- The accumulator in `completeInputs` receives `Cell` objects (from signer's `findCellsOnChain`), which always have `outPoint` -- `infoFrom` is called with these individual `Cell` objects during completion -- override automatically participates -- Throws `ErrorUdtInsufficientCoin` if insufficient balance (not capacity -- capacity is a soft constraint) - -### completeInputs (Low-Level) - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:1309-1331` - -```typescript -async completeInputs( - txLike: ccc.TransactionLike, - from: ccc.Signer, - accumulator: (acc: T, v: ccc.Cell, ...) => Promise | T | undefined, - init: T, -): Promise<{ tx: ccc.Transaction; addedCount: number; accumulated?: T }> { - const tx = ccc.Transaction.from(txLike); - const res = await tx.completeInputs(from, this.filter, accumulator, init); - return { ...res, tx }; -} -``` - -**Key finding:** Delegates to `tx.completeInputs(from, this.filter, ...)` which uses the Udt's `filter` to find cells via the signer. The `filter` only matches xUDT cells. Receipt and deposit cells must be pre-added to the transaction by the caller. - -## CellAny vs Cell: outPoint and capacityFree - -### CellAnyLike type - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:313-318` - -```typescript -export type CellAnyLike = { - outPoint?: OutPointLike | null; - previousOutput?: OutPointLike | null; - cellOutput: CellOutputLike; - outputData?: HexLike | null; -}; -``` - -- `outPoint` is `OutPointLike | null | undefined` -- explicitly optional - -### CellAny class - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:331-457` - -```typescript -export class CellAny { - public outPoint: OutPoint | undefined; // line 332 - - constructor( - public cellOutput: CellOutput, - public outputData: Hex, - outPoint?: OutPoint, // line 346: optional - ) { - this.outPoint = outPoint; // line 347 - } -} -``` - -- `outPoint` is `OutPoint | undefined` at the class level -- Constructor parameter `outPoint` is optional -- defaults to `undefined` - -### CellAny.from() factory - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:374-386` - -```typescript -static from(cell: CellAnyLike): CellAny { - if (cell instanceof CellAny) { return cell; } - const outputData = hexFrom(cell.outputData ?? "0x"); - return new CellAny( - CellOutput.from(cell.cellOutput, outputData), - outputData, - apply(OutPoint.from, cell.outPoint ?? cell.previousOutput), - ); -} -``` - -- Uses `apply(OutPoint.from, cell.outPoint ?? cell.previousOutput)` -- if both are null/undefined, `outPoint` is `undefined` - -### CellAny.capacityFree - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:404-405` - -```typescript -get capacityFree() { - return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize); -} -``` - -**Confirmed:** `capacityFree` is a getter on `CellAny` -- available on ALL cells, both input and output. No need to construct `Cell` to access `capacityFree`. The getter computes `capacity - fixedPointFrom(occupiedSize)` where `occupiedSize` is `cellOutput.occupiedSize + bytesFrom(outputData).byteLength`. - -### Cell class (extends CellAny) - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:488-503` - -```typescript -export class Cell extends CellAny { - constructor( - public outPoint: OutPoint, // line 498: NOT optional - cellOutput: CellOutput, - outputData: Hex, - ) { - super(cellOutput, outputData, outPoint); - } -} -``` - -- `Cell.outPoint` is `OutPoint` (non-optional) -- always present -- `Cell extends CellAny` -- a `Cell` is a `CellAny` with guaranteed `outPoint` - -### CellInput.getCell() - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:861-872` - -```typescript -async getCell(client: Client): Promise { - await this.completeExtraInfos(client); - if (!this.cellOutput || !this.outputData) { - throw new Error("Unable to complete input"); - } - return Cell.from({ - outPoint: this.previousOutput, - cellOutput: this.cellOutput, - outputData: this.outputData, - }); -} -``` - -**Confirmed:** Returns `Cell.from(...)` with `outPoint: this.previousOutput`. Since `CellInput.previousOutput` is always an `OutPoint`, the returned `Cell` always has `outPoint` set. - -### tx.outputCells getter - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:1715-1728` - -```typescript -get outputCells(): Iterable { - const { outputs, outputsData } = this; - function* generator(): Generator { - for (let i = 0; i < outputs.length; i++) { - yield CellAny.from({ - cellOutput: outputs[i], - outputData: outputsData[i] ?? "0x", - }); - } - } - return generator(); -} -``` - -**Confirmed:** Output cells are created via `CellAny.from({ cellOutput, outputData })` -- no `outPoint` is passed, so `outPoint` is `undefined`. - -### Summary: outPoint as Input/Output Discriminator - -| Source | Type | outPoint | -|--------|------|----------| -| `getInputsInfo` -> `input.getCell(client)` | `Cell` | Always `OutPoint` | -| `getOutputsInfo` -> `tx.outputCells` | `CellAny` | Always `undefined` | -| `completeInputs` accumulator (new cells found) | `Cell` | Always `OutPoint` | - -**Verdict:** Checking `cell.outPoint` in `infoFrom` reliably distinguishes input cells from output cells. This is structural, not accidental -- `Cell` requires `outPoint`, and output generators never provide one. - -## UdtInfo Migration Mapping - -### UdtInfo structure - -**File:** `forks/ccc/packages/udt/src/udt/index.ts:218-292` - -```typescript -export class UdtInfo { - constructor( - public balance: ccc.Num, // UDT balance - public capacity: ccc.Num, // total CKB capacity of UDT cells - public count: number, // number of UDT cells - ) {} - - addAssign(infoLike: UdtInfoLike) { - const info = UdtInfo.from(infoLike); - this.balance += info.balance; - this.capacity += info.capacity; - this.count += info.count; - return this; - } -} -``` - -### Migration from [FixedPoint, FixedPoint] - -Current `IckbUdtManager.getInputsUdtBalance()` returns `[ccc.FixedPoint, ccc.FixedPoint]`: -- `[0]`: Total UDT balance (iCKB amount) -- maps to `UdtInfo.balance` -- `[1]`: Total CKB capacity -- maps to `UdtInfo.capacity` - -CCC `UdtInfo` adds `count` (number of cells) which has no equivalent in the current code. This is purely additive -- the override just tracks it alongside balance and capacity. - -| Current (IckbUdtManager) | CCC (UdtInfo) | Notes | -|---------------------------|---------------|-------| -| `acc[0]` (udtValue) | `info.balance` | Same semantics: total iCKB amount | -| `acc[1]` (capacity) | `info.capacity` | Same semantics: total CKB capacity | -| N/A | `info.count` | New field: count of cells contributing | -| `[0n, 0n]` initial | `UdtInfo.from(acc).clone()` | UdtInfo.from(undefined) defaults to `{balance: 0n, capacity: 0n, count: 0}` | - -### addAssign for accumulation - -Current code uses `return [udtValue + amount, capacity + cellCapacity]` tuple pattern. -CCC uses `acc.addAssign({ balance, capacity, count: 1 })` method pattern. - -Key difference: `addAssign` mutates in place and returns `this`. The override must use `addAssign` for each cell type (xUDT, receipt, deposit) to maintain compatibility with the accumulator pattern in `completeInputsByBalance`. - -## Header Access Verification - -### client.getTransactionWithHeader() - -**File:** `forks/ccc/packages/core/src/client/client.ts:631-661` - -```typescript -async getTransactionWithHeader( - txHashLike: HexLike, -): Promise< - | { transaction: ClientTransactionResponse; header?: ClientBlockHeader } - | undefined -> { - const txHash = hexFrom(txHashLike); - const tx = await this.cache.getTransactionResponse(txHash); - if (tx?.blockHash) { - const header = await this.getHeaderByHash(tx.blockHash); - if (header && this.cache.hasHeaderConfirmed(header)) { - return { transaction: tx, header }; - } - } - - const res = await this.getTransactionNoCache(txHash); - if (!res) { return; } - - await this.cache.recordTransactionResponses(res); - return { - transaction: res, - header: res.blockHash - ? await this.getHeaderByHash(res.blockHash) - : undefined, - }; -} -``` - -**Confirmed:** -- Returns `{ transaction: ClientTransactionResponse, header?: ClientBlockHeader } | undefined` -- `header` is a `ClientBlockHeader` which contains `dao` field with `ar` (accumulate rate) needed for `ickbValue()` -- First checks cache: `this.cache.getTransactionResponse(txHash)` -- if cached and header confirmed, returns immediately -- Falls back to network fetch: `this.getTransactionNoCache(txHash)`, then caches the response -- Subsequent calls for the same txHash are served from cache -- no redundant network requests - -### client.getCellWithHeader() - -**File:** `forks/ccc/packages/core/src/client/client.ts:212-234` - -```typescript -async getCellWithHeader( - outPointLike: OutPointLike, -): Promise<{ cell: Cell; header?: ClientBlockHeader } | undefined> { - const outPoint = OutPoint.from(outPointLike); - const res = await this.getTransactionWithHeader(outPoint.txHash); - // ... extracts cell from transaction output ... - return { cell, header }; -} -``` - -**Confirmed:** `getCellWithHeader` is a convenience wrapper around `getTransactionWithHeader`. Either can be used in `infoFrom` -- `getTransactionWithHeader` is more direct since we already have `outPoint.txHash`. - -### Caching behavior - -The `Client.cache` is checked first in `getTransactionWithHeader`. The `cache.recordTransactionResponses()` call ensures that fetched transactions are cached. This means: -- First call for a txHash: network fetch + cache store -- Subsequent calls: cache hit, no network -- Multiple receipt/deposit cells from the same transaction share the same cached header - -This is transparent to the `infoFrom` override -- just call `client.getTransactionWithHeader()` and the cache handles the rest. - -## PR #328 Compatibility - -### FeePayer abstract class - -**File:** `forks/ccc/packages/core/src/signer/feePayer/feePayer.ts:14-72` - -```typescript -export abstract class FeePayer { - constructor(protected client_: Client) {} - - abstract completeTxFee( - txLike: TransactionLike, - options?: FeeRateOptionsLike, - ): Promise; - - abstract completeInputs( - tx: Transaction, - filter: ClientCollectableSearchKeyFilterLike, - accumulator: (acc: T, v: Cell, ...) => Promise | T | undefined, - init: T, - ): Promise<{ addedCount: number; accumulated?: T }>; - - async prepareTransaction(tx: TransactionLike): Promise { - return Transaction.from(tx); - } -} -``` - -### Transaction.completeByFeePayer() - -**File:** `forks/ccc/packages/core/src/ckb/transaction.ts:2264-2275` - -```typescript -async completeByFeePayer(...feePayers: FeePayer[]): Promise { - let tx = this.clone(); - for (const feePayer of feePayers) { - tx = await feePayer.prepareTransaction(tx); - } - for (const feePayer of feePayers) { - await feePayer.completeTxFee(tx); - } - this.copy(tx); -} -``` - -### Compatibility Assessment - -The `infoFrom` override operates at a level below the completion plumbing. The call chain is: - -1. `completeInputsByBalance` -> `getInputsInfo` -> `infoFrom` (for existing inputs) -2. `completeInputsByBalance` -> `getOutputsInfo` -> `infoFrom` (for outputs) -3. `completeInputsByBalance` -> `completeInputs` -> `tx.completeInputs(from, this.filter, ...)` -> `from.completeInputs(...)` which goes to Signer or FeePayer -4. Within the accumulator: `infoFrom` is called per new cell found - -The FeePayer change affects step 3: how `completeInputs` finds and adds cells. It does NOT affect: -- How `getInputsInfo` resolves inputs to cells (still `input.getCell(client)`) -- How `getOutputsInfo` iterates outputs (still `tx.outputCells`) -- How `infoFrom` processes cells (per-cell logic, unchanged) -- The `infoFrom` signature or semantics - -**Verdict: Fully compatible.** The `infoFrom` override works with both: -- Current architecture: `from.completeInputs(this, filter, accumulator, init)` via Signer -- PR #328 architecture: `feePayer.completeInputs(tx, filter, accumulator, init)` via FeePayer - -The override point is insulated from the completion routing layer. - -## Open Questions Resolved - -### 1. Receipt/Deposit Cell Discovery in completeInputsByBalance - -**Question:** Should `IckbUdt` override `completeInputsByBalance` to also search for receipt/deposit cells? - -**Answer: No -- caller responsibility is confirmed correct.** - -**Evidence:** `Udt.completeInputs` (line 1325) delegates to `tx.completeInputs(from, this.filter, accumulator, init)`. The `this.filter` is hardcoded at construction to match only xUDT cells by type script. There is no multi-filter mechanism in `completeInputs`. - -The current architecture already handles this correctly: -- `LogicManager.completeDeposit()` adds receipt/deposit cells to the transaction -- `OwnedOwnerManager.requestWithdrawal()` adds deposit cells -- `IckbUdt.infoFrom()` then accurately VALUES these cells when `getInputsInfo`/`getOutputsInfo` processes them - -Overriding `completeInputsByBalance` to perform multiple filter searches would: -1. Require reimplementing the dual-constraint optimization logic (balance + capacity deficit) -2. Fight CCC's single-filter design pattern -3. Duplicate cell discovery logic that already exists in `LogicManager` and `OwnedOwnerManager` - -**Recommendation confirmed:** `IckbUdt` overrides only `infoFrom` for accurate balance calculation. Cell discovery is the caller's responsibility. - -### 2. capacityFree on CellAny vs Cell - -**Question:** Does `CellAny` have `capacityFree`? - -**Answer: Yes -- confirmed at transaction.ts:404-405.** - -```typescript -// CellAny class, line 404-405 -get capacityFree() { - return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize); -} -``` - -`CellAny.occupiedSize` (line 394-396) = `this.cellOutput.occupiedSize + bytesFrom(this.outputData).byteLength` - -Since `Cell extends CellAny`, both classes have `capacityFree`. No need to construct `Cell` for capacity computation. - -However, `DaoManager.isDeposit()` (`packages/dao/src/dao.ts:30`) requires `ccc.Cell` (not `CellAny`): - -```typescript -isDeposit(cell: ccc.Cell): boolean { - const { cellOutput: { type }, outputData } = cell; - return outputData === DaoManager.depositData() && type?.eq(this.script) === true; -} -``` - -The `ccc.Cell` requirement is a type constraint -- `isDeposit` only reads `cellOutput` and `outputData`, not `outPoint`. But since `Cell.from()` requires `outPoint`, and deposit cells in `infoFrom` always have `outPoint` (they are input cells), constructing `Cell.from({ outPoint: cell.outPoint, cellOutput: cell.cellOutput, outputData: cell.outputData })` is safe and straightforward. - -### 3. PR #328 FeePayer Integration - -**Question:** Does `IckbUdt` need special handling for the FeePayer transition? - -**Answer: No -- confirmed by code trace above** (see "PR #328 Compatibility" section). - -The `infoFrom` override operates below the completion routing layer. Whether cells arrive via `Signer.completeInputs` or `FeePayer.completeInputs`, they flow through the same `getInputsInfo` -> `infoFrom` chain. - -### 4. Conservation Law Enforcement in IckbUdt - -**Question:** Should IckbUdt enforce the conservation law at build time? - -**Answer: Accurate balance reporting is sufficient; enforcement is out of scope for the Udt subclass.** - -**Evidence:** The conservation law is `Input UDT + Input Receipts = Output UDT + Input Deposits`. With `infoFrom` correctly valuing all three cell types: - -- `getInputsInfo` returns: xUDT balance + receipt value - deposit value (for inputs) -- `getOutputsInfo` returns: xUDT balance (for outputs, since receipt/deposit outputs don't carry iCKB value) -- `getBalanceBurned` (inherited, line 1257-1266) = inputs - outputs - -If the conservation law holds, `getBalanceBurned` returns 0 (or the intended burn amount). Callers can check this before submitting. - -Embedding enforcement in `infoFrom` would: -1. Conflate balance calculation with validation -2. Prevent legitimate partial-construction scenarios where the transaction is not yet balanced -3. Break the `completeInputsByBalance` loop which expects `infoFrom` to report current state, not validate final state - -**Recommendation confirmed:** Start with accurate balance reporting only. Validation can be added as a separate method (e.g., `assertConservationLaw(client, tx)`) if needed later. - -## IckbUdtManager -> IckbUdt Override Mapping - -### Line-by-line mapping - -**Current:** `IckbUdtManager.getInputsUdtBalance()` at `packages/core/src/udt.ts:66-141` -**Target:** `IckbUdt.infoFrom()` override - -| Current Code (IckbUdtManager) | infoFrom Override | Notes | -|-------------------------------|-------------------|-------| -| `const tx = ccc.Transaction.from(txLike)` | N/A -- `infoFrom` receives cells directly, not a transaction | Transaction handling is in `getInputsInfo`/`getOutputsInfo` | -| `ccc.reduceAsync(tx.inputs, async (acc, input) => { ... }, [0n, 0n])` | `for (const cellLike of [cells].flat()) { ... }` on `UdtInfo` accumulator | Iteration pattern differs -- `infoFrom` gets pre-resolved cells | -| `await input.completeExtraInfos(client)` | N/A -- cells are already resolved when `infoFrom` is called | `getInputsInfo` handles resolution via `input.getCell(client)` | -| `const { previousOutput: outPoint, cellOutput, outputData } = input` | `const cell = ccc.CellAny.from(cellLike)` then `cell.outPoint`, `cell.cellOutput`, `cell.outputData` | Property access pattern changes | -| `if (!cellOutput \|\| !outputData) throw ...` | N/A -- `CellAny.from()` always produces valid `cellOutput` and `outputData` (defaults to `"0x"`) | Error case eliminated by type system | -| `if (!type) return acc` | Handled by `this.isUdt(cell)` returning false for typeless cells | Implicit in isUdt check | -| `const cell = new ccc.Cell(outPoint, cellOutput, outputData)` | `const cell = ccc.CellAny.from(cellLike)` -- for `isDeposit`, construct `Cell.from(...)` when needed | Only need `Cell` for `isDeposit()` call | -| `if (this.isUdt(cell)) { return [udtValue + numFromBytes(...), capacity + ...] }` | `if (this.isUdt(cell)) { info.addAssign({ balance: Udt.balanceFromUnsafe(...), capacity: ..., count: 1 }) }` | Use `balanceFromUnsafe` instead of manual `numFromBytes(bytesFrom(outputData).slice(0, 16))` | -| `if (this.logicScript.eq(type)) { // receipt ... }` | Same logic: check `cell.cellOutput.type?.eq(this.logicScript)` | Receipt detection unchanged | -| `client.getTransactionWithHeader(outPoint.txHash)` | `client.getTransactionWithHeader(cell.outPoint!.txHash)` | `outPoint` available since receipt cells are inputs (verified above) | -| `ReceiptData.decode(outputData)` | `ReceiptData.decode(cell.outputData)` | Direct access to `outputData` | -| `ickbValue(depositAmount, header) * depositQuantity` | Same computation | `ickbValue` function unchanged | -| `return [udtValue + receiptValue, capacity + ...]` | `info.addAssign({ balance: receiptValue, capacity: ..., count: 1 })` | Use addAssign pattern | -| `if (this.logicScript.eq(lock) && this.daoManager.isDeposit(cell))` | Check `cell.cellOutput.lock.eq(this.logicScript)` then construct `Cell.from(...)` for `isDeposit` | Need Cell construction for `isDeposit` | -| `ickbValue(cell.capacityFree, header)` | `ickbValue(cell.capacityFree, header)` -- `capacityFree` available on `CellAny` | Direct access, no Cell needed for capacity | -| `return [udtValue - depositValue, capacity + ...]` | `info.addAssign({ balance: -depositValue, capacity: ..., count: 1 })` | Negative balance via addAssign | -| Output cells: handled by separate `getOutputsUdtBalance` | Output cells flow through same `infoFrom` -- only `isUdt` check matches (no receipt/deposit for outputs) | Unified by `outPoint` check: `if (!cell.outPoint) continue` for receipt/deposit logic | - -### Key behavioral difference: Outputs - -Current `IckbUdtManager` has separate methods: -- `getInputsUdtBalance()`: processes xUDT + receipt + deposit inputs -- No explicit output override -- `UdtManager.getOutputsUdtBalance()` handles standard xUDT outputs - -New `IckbUdt.infoFrom()` handles BOTH inputs and outputs in a single method. For output cells (no `outPoint`), only the `isUdt` check applies -- receipt/deposit output cells are skipped because: -1. `cell.outPoint` is `undefined` for outputs -2. Receipt/deposit logic is gated behind `if (!cell.outPoint) continue` -3. The base `isUdt` check catches standard xUDT output cells - -This is correct because: -- iCKB receipt outputs are newly created receipts (by `LogicManager.deposit`), not value carriers for balance -- iCKB deposit outputs have DAO type script, not iCKB UDT type script -- `isUdt` returns false -- Only standard xUDT outputs carry iCKB value in the output direction - -### Constructor migration - -| Current (IckbUdtManager) | Target (IckbUdt) | Notes | -|--------------------------|-------------------|-------| -| `constructor(script, cellDeps, logicScript, daoManager)` | `constructor(code, script, logicScript, daoManager, config?)` | New `code` param (OutPoint for cell deps), `config` optional | -| `super(script, cellDeps, "iCKB", "iCKB", 8)` | `super(code, script, config)` | Base class changes: UdtManager -> Udt | -| `this.logicScript` | `this.logicScript` | Preserved | -| `this.daoManager` | `this.daoManager` | Preserved | -| N/A | `this.script` (from Udt base) | Replaces `UdtManager.script` | -| `this.cellDeps` | `this.code` (OutPoint) + `addCellDeps()` | CCC uses OutPoint for code dep, not explicit CellDep array | -| `this.name`, `this.symbol`, `this.decimals` | Via `udt.name()`, `udt.symbol()`, `udt.decimals()` (SSRI) or custom properties | Metadata access changes | - -## Edge Cases and Risks - -### 1. CellAny.from() coerces both outPoint and previousOutput - -**File:** `transaction.ts:384` -```typescript -apply(OutPoint.from, cell.outPoint ?? cell.previousOutput), -``` - -If a `CellAnyLike` has `previousOutput` but not `outPoint`, the resulting `CellAny` still gets `outPoint` set. This is safe -- both names refer to the same concept. But within `infoFrom`, always check `cell.outPoint` (not `cell.previousOutput`, which doesn't exist on `CellAny`). - -### 2. DaoManager.isDeposit() type requirement - -`DaoManager.isDeposit()` accepts `ccc.Cell`, not `CellAny`. Since deposit cells are only relevant as inputs (where `outPoint` is always present), constructing `Cell.from({ outPoint: cell.outPoint!, cellOutput: cell.cellOutput, outputData: cell.outputData })` is always valid. The non-null assertion on `outPoint` is safe because the deposit check is gated behind `if (!cell.outPoint) continue`. - -### 3. UdtInfo.balance allows negative values - -`UdtInfo.balance` is `ccc.Num` (bigint), not unsigned. The `addAssign` method does `this.balance += info.balance`. For deposit cells, passing `balance: -depositIckbValue` works because bigint addition with negative values is well-defined. This is tested by `completeInputsByBalance` which checks `info.balance >= ccc.Zero` as its termination condition -- negative balance contributions from deposits are correctly accumulated. - -### 4. Cell discovery gap: completeInputsByBalance only finds xUDT cells - -As documented in Open Question #1, `Udt.filter` only matches xUDT cells. If a caller relies solely on `completeInputsByBalance` to provide all iCKB value, receipt and deposit cells will be missed. This is by design -- callers must pre-add receipt/deposit cells (via `LogicManager`/`OwnedOwnerManager`) before calling `completeInputsByBalance`. - -Risk mitigation: Document this clearly in `IckbUdt` API documentation. The `completeInputsByBalance` inherited method correctly accounts for pre-added receipt/deposit inputs via `getInputsInfo` -> `infoFrom`. - -### 5. Async infoFrom and potential performance - -The base `infoFrom` is synchronous (returns `Promise` but internally uses `.reduce()` without `await`). The override will be truly async due to `client.getTransactionWithHeader()` calls. This changes `infoFrom` from O(1) network calls to O(n) where n is the number of receipt/deposit cells in the input. - -Mitigation: -- CCC `Client.cache` ensures each txHash is fetched at most once per session -- Receipt/deposit cells are typically few per transaction (1-5) -- Multiple cells from the same transaction share one cached header fetch -- The async signature is already declared on the base class, so no interface change needed - -### 6. No upstream CCC changes required - -The investigation confirms that `IckbUdt extends udt.Udt` with `infoFrom` override requires ZERO changes to CCC's Udt class. All override points are public methods with appropriate signatures. This eliminates the dealbreaker risk identified in CONTEXT.md. - ---- - -*Investigation: Phase 03-ccc-udt-integration-investigation, Plan 01* -*Completed: 2026-02-24* diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-01-PLAN.md b/.planning/phases/03-ccc-udt-integration-investigation/03-01-PLAN.md deleted file mode 100644 index 16ac974..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-01-PLAN.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -phase: 03-ccc-udt-integration-investigation -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md -autonomous: true -requirements: - - UDT-01 - - UDT-02 - -must_haves: - truths: - - "Every CCC Udt method chain (getInputsInfo -> infoFrom, getOutputsInfo -> infoFrom, completeInputsByBalance -> getInputsInfo/getOutputsInfo) is traced with exact line references showing how cells flow" - - "The outPoint presence/absence mechanism for distinguishing input vs output cells in infoFrom is verified with concrete code evidence from CCC source" - - "The async infoFrom override with header fetches is confirmed compatible with CCC's completion loop" - - "All open questions from 03-RESEARCH.md (filter mismatch, capacityFree on CellAny, PR #328 compatibility, conservation law enforcement) are answered with code evidence" - - "The IckbUdtManager -> IckbUdt migration path is mapped: constructor parameters, method signature changes, return type differences (UdtInfo vs [FixedPoint, FixedPoint])" - artifacts: - - path: ".planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md" - provides: "Detailed source code trace findings with exact line references and code snippets" - contains: "## CCC Udt Method Chain Trace" - key_links: - - from: "forks/ccc/packages/udt/src/udt/index.ts" - to: "packages/core/src/udt.ts" - via: "infoFrom override replacing getInputsUdtBalance" - pattern: "infoFrom.*CellAnyLike" ---- - - -Trace CCC Udt class internals end-to-end against actual source code and verify the feasibility of the `IckbUdt extends udt.Udt` approach identified in 03-RESEARCH.md. Resolve all open questions. - -Purpose: Provide verified, source-code-backed evidence for the decision document (Plan 02). The research identified `infoFrom` as the optimal override point -- this plan validates that finding by tracing real method chains and checking edge cases. - -Output: `03-01-INVESTIGATION.md` -- structured findings with exact line references, code snippets, and answers to each open question. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/03-ccc-udt-integration-investigation/03-CONTEXT.md -@.planning/phases/03-ccc-udt-integration-investigation/03-RESEARCH.md - - - - - - Task 1: Trace CCC Udt internals and verify override feasibility - .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md - -Read and trace the following CCC source files end-to-end to verify research findings: - -1. **Udt class and infoFrom** (`forks/ccc/packages/udt/src/udt/index.ts`): - - Trace `infoFrom()` signature, return type, how it accumulates `UdtInfo` - - Trace `getInputsInfo()` -- how it resolves `CellInput` to `Cell` via `input.getCell(client)`, confirm output `Cell` objects have `outPoint` set - - Trace `getOutputsInfo()` -- how it iterates `tx.outputCells`, confirm yielded `CellAny` objects lack `outPoint` - - Trace `completeInputsByBalance()` -- full chain through `getInputsInfo`/`getOutputsInfo`/`infoFrom`, how balance deficit drives completion - - Check `Udt` constructor -- what `filter` is set to, confirm it only matches xUDT cells - - Check `isUdt()` method -- how it differs from the current `UdtManager.isUdt()` in `@ickb/utils` - - Check `Udt.balanceFromUnsafe()` -- how it reads UDT balance from output data - -2. **CellAny and Cell types** (`forks/ccc/packages/core/src/ckb/transaction.ts`): - - Verify `CellAny.outPoint` is `OutPoint | undefined` (not nullable) - - Verify `CellAny` vs `Cell` -- confirm `CellAny` has `capacityFree` getter (pre-resolved: transaction.ts:404-405) - - Check `Cell.capacityFree` -- exact computation (capacity - occupiedSize) - - Check `CellInput.getCell(client)` -- confirm returned Cell has outPoint set - - Check `tx.outputCells` getter -- confirm yielded values are `CellAny` without outPoint - -3. **UdtInfo type** (`forks/ccc/packages/udt/src/udt/index.ts` or related): - - Trace `UdtInfo` fields: balance, capacity, count - - Trace `UdtInfo.addAssign()` method - - Compare with current `IckbUdtManager.getInputsUdtBalance()` return type `[FixedPoint, FixedPoint]` -- map the migration - -4. **Header access** (`forks/ccc/packages/core/src/client/client.ts`): - - Verify `client.getTransactionWithHeader(txHash)` returns `{ transaction, header? }` where header has `.dao.ar` - - Confirm CCC Client.cache handles repeated calls transparently - -5. **PR #328 compatibility check** (`forks/ccc/packages/core/src/signer/feePayer/`): - - Check whether PR #328's FeePayer changes affect `infoFrom` or `getInputsInfo`/`getOutputsInfo` method signatures - - Confirm `infoFrom` override is compatible with both current and PR #328 architectures - -6. **Current IckbUdtManager analysis** (`packages/core/src/udt.ts`, `packages/utils/src/udt.ts`): - - Map each line of `IckbUdtManager.getInputsUdtBalance()` to the equivalent `infoFrom` override logic - - Identify the `UdtManager.isUdt()` check -- verify compatibility with CCC `Udt.isUdt()` - - Note: current `getInputsUdtBalance` iterates `tx.inputs` with `completeExtraInfos` -- CCC `getInputsInfo` uses `input.getCell(client)` instead. Verify these are equivalent. - - Identify what `getOutputsUdtBalance()` does for iCKB -- it only counts xUDT output cells (no receipt/deposit outputs carry iCKB value), so the base `infoFrom` logic for outputs should work unchanged - -Write findings as `03-01-INVESTIGATION.md` with these sections: -- **## CCC Udt Method Chain Trace** -- with exact file:line references and key code snippets -- **## CellAny vs Cell: outPoint and capacityFree** -- verified behavior with evidence -- **## UdtInfo Migration Mapping** -- how [FixedPoint, FixedPoint] maps to UdtInfo -- **## Header Access Verification** -- confirmed API and caching -- **## PR #328 Compatibility** -- confirmed or flagged -- **## Open Questions Resolved** -- answers to each open question from 03-RESEARCH.md with code evidence -- **## IckbUdtManager -> IckbUdt Override Mapping** -- line-by-line mapping of current logic to infoFrom override -- **## Edge Cases and Risks** -- any issues discovered during trace - - - test -f .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md && grep -q "## CCC Udt Method Chain Trace" .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md && grep -q "## Open Questions Resolved" .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md && grep -q "## IckbUdtManager -> IckbUdt Override Mapping" .planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md && echo "PASS" - Verify investigation references actual CCC source line numbers and includes code snippets for each finding - - - - Every CCC Udt method chain is traced with file:line references - - outPoint presence/absence mechanism verified with CellAny/Cell source evidence - - capacityFree availability on CellAny answered definitively - - UdtInfo fields mapped to current [FixedPoint, FixedPoint] return type - - PR #328 compatibility confirmed or risks flagged - - All 4 open questions from 03-RESEARCH.md answered with code evidence - - Line-by-line mapping from IckbUdtManager.getInputsUdtBalance to infoFrom override exists - - - - - - -- `03-01-INVESTIGATION.md` exists with all required sections -- Each finding includes a source file path and line number reference -- All open questions from 03-RESEARCH.md are addressed -- The IckbUdtManager -> IckbUdt mapping is complete (no unmapped logic) - - - -The investigation document provides sufficient verified evidence for Plan 02 to write a confident decision document. Every claim from 03-RESEARCH.md is either confirmed or corrected with source code evidence. - - - -After completion, create `.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md` - diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md b/.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md deleted file mode 100644 index 410583c..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -phase: 03-ccc-udt-integration-investigation -plan: 01 -subsystem: udt -tags: [ccc, udt, subclass, infoFrom, override, header-access] - -# Dependency graph -requires: - - phase: 01-ickb-utils-smarttransaction-removal - provides: "IckbUdtManager with TransactionLike pattern, DaoManager with isDeposit()" - - phase: 02-ccc-utility-adoption - provides: "Clean codebase without deprecated CCC APIs" -provides: - - "Verified source-code-backed evidence for IckbUdt extends udt.Udt feasibility" - - "Complete infoFrom override mapping from IckbUdtManager.getInputsUdtBalance()" - - "Confirmed PR #328 compatibility, header access pattern, and outPoint discriminator" -affects: [03-02-decision-document, 04-deprecated-api-replacement, 05-ickb-udt-implementation] - -# Tech tracking -tech-stack: - added: [] - patterns: - - "infoFrom override: per-cell balance calculation with outPoint-based input/output discrimination" - - "UdtInfo accumulator: addAssign pattern replacing tuple accumulation" - -key-files: - created: - - ".planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md" - modified: [] - -key-decisions: - - "infoFrom is the sole override point -- no need to override getInputsInfo/getOutputsInfo" - - "No upstream CCC changes required for IckbUdt subclass" - - "Caller responsibility for receipt/deposit cell discovery (not IckbUdt's filter)" - - "Accurate balance reporting only -- conservation law enforcement is separate" - -patterns-established: - - "outPoint presence/absence as input/output cell discriminator in infoFrom" - - "DaoManager.isDeposit() requires Cell construction from CellAny when outPoint present" - - "UdtInfo.balance supports negative values for deposit cell subtraction" - -requirements-completed: [UDT-01, UDT-02] - -# Metrics -duration: 5min -completed: 2026-02-24 ---- - -# Phase 3 Plan 1: CCC Udt Investigation Summary - -**End-to-end CCC Udt method chain trace confirming infoFrom as optimal override point for IckbUdt subclass -- all open questions resolved with source code evidence, no upstream CCC changes needed** - -## Performance - -- **Duration:** 5 min -- **Started:** 2026-02-24T11:19:15Z -- **Completed:** 2026-02-24T11:23:54Z -- **Tasks:** 1 -- **Files modified:** 1 - -## Accomplishments -- Traced every CCC Udt method chain (infoFrom, getInputsInfo, getOutputsInfo, completeInputsByBalance, completeInputs) with exact file:line references -- Verified outPoint presence/absence as reliable input/output cell discriminator (CellInput.getCell always sets outPoint; tx.outputCells never does) -- Confirmed capacityFree available on CellAny (transaction.ts:404-405) -- no Cell construction needed for deposit cell iCKB value -- Mapped UdtInfo fields to current [FixedPoint, FixedPoint] return type with addAssign migration pattern -- Confirmed PR #328 FeePayer compatibility -- infoFrom operates below the completion routing layer -- Resolved all 4 open questions from 03-RESEARCH.md with code evidence -- Created complete line-by-line mapping from IckbUdtManager.getInputsUdtBalance to infoFrom override - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Trace CCC Udt internals and verify override feasibility** - `b2827e5` (docs) - -## Files Created/Modified -- `.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md` - Detailed source code trace findings with exact line references, code snippets, migration mapping, and resolved open questions - -## Decisions Made -- **infoFrom is the sole override point:** No need to override getInputsInfo or getOutputsInfo -- infoFrom handles both input and output cells uniformly via outPoint check -- **No upstream CCC changes required:** The Udt class API surface is sufficient for IckbUdt subclassing without modification -- **Caller responsibility for cell discovery:** IckbUdt.filter only matches xUDT cells; receipt/deposit cells must be pre-added by LogicManager/OwnedOwnerManager -- **Accurate balance reporting only:** Conservation law enforcement is separate from infoFrom -- can be added as validation method later - -## Deviations from Plan - -None -- plan executed exactly as written. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- Investigation provides complete evidence base for Plan 02 (decision document) -- All source code references verified and documented -- Migration mapping is complete -- no unmapped logic from IckbUdtManager -- Ready to write confident decision document recommending IckbUdt extends udt.Udt - -## Self-Check: PASSED - -- FOUND: `.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md` -- FOUND: `.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md` -- FOUND: commit `b2827e5` - ---- -*Phase: 03-ccc-udt-integration-investigation* -*Completed: 2026-02-24* diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-02-PLAN.md b/.planning/phases/03-ccc-udt-integration-investigation/03-02-PLAN.md deleted file mode 100644 index 2c281d2..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-02-PLAN.md +++ /dev/null @@ -1,212 +0,0 @@ ---- -phase: 03-ccc-udt-integration-investigation -plan: 02 -type: execute -wave: 2 -depends_on: - - "03-01" -files_modified: - - .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md -autonomous: true -requirements: - - UDT-01 - - UDT-02 - - UDT-03 - -must_haves: - truths: - - "A feasibility assessment exists answering whether IckbUdt extends udt.Udt can override infoFrom to account for receipt cells and deposit cells alongside xUDT cells" - - "The header access pattern for receipt/deposit value calculation is designed with specific API calls and async flow documented" - - "A clear decision is documented with one of three outcomes (subclass, custom, hybrid) and rationale for the chosen path" - - "The conservation law preservation strategy is documented (how sign conventions and cell type handling maintain Input UDT + Input Receipts = Output UDT + Input Deposits)" - - "The cell discovery vs balance calculation boundary is defined (what infoFrom handles vs what callers handle)" - - "The decision document provides sufficient detail for Phase 4 and Phase 5 implementers to proceed without ambiguity" - artifacts: - - path: ".planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md" - provides: "Formal decision document covering UDT-01 (feasibility), UDT-02 (header pattern), UDT-03 (decision)" - contains: "## Decision" - key_links: - - from: ".planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md" - to: ".planning/ROADMAP.md" - via: "Decision outcome determines Phase 4 and Phase 5 approach" - pattern: "Phase [45]" ---- - - -Write the formal decision document synthesizing the investigation findings into actionable outcomes for UDT-01, UDT-02, and UDT-03. This document directly determines how Phases 4 and 5 implement UDT handling. - -Purpose: Close Phase 3's investigation with a clear, justified decision that eliminates ambiguity for downstream phases. - -Output: `03-DECISION.md` -- the formal feasibility assessment, header access pattern design, and decision with rationale. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/03-ccc-udt-integration-investigation/03-CONTEXT.md -@.planning/phases/03-ccc-udt-integration-investigation/03-RESEARCH.md -@.planning/phases/03-ccc-udt-integration-investigation/03-01-SUMMARY.md - - - - - - Task 1: Write feasibility assessment and header access pattern (UDT-01, UDT-02) - .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md - -Using the verified findings from `03-01-INVESTIGATION.md` (via 03-01-SUMMARY.md), write the first two sections of the decision document: - -**## Feasibility Assessment (UDT-01)** - -Structure as a clear YES/NO/CONDITIONAL answer with supporting evidence: - -1. **Override Point**: Which override point (`infoFrom` vs `getInputsInfo`/`getOutputsInfo`) and why. Reference specific findings from the investigation. - -2. **Three Cell Types in infoFrom**: - - xUDT cells: How `isUdt()` identifies them, how balance is read (reference CCC's `balanceFromUnsafe` vs current `ccc.numFromBytes` approach) - - Receipt cells: How type script matching identifies them, how `ReceiptData.decode` + `ickbValue()` computes value, positive balance contribution - - Deposit cells: How lock script matching + `isDeposit()` identifies them, how `ickbValue(capacityFree)` computes value, NEGATIVE balance contribution (conservation law sign convention) - -3. **Input vs Output Distinction**: How outPoint presence/absence in `infoFrom` cleanly separates input cells (receipt/deposit relevant) from output cells (xUDT only). Reference CellAny investigation findings. - -4. **capacityFree Resolution**: How to access unoccupied capacity for deposit cells within `infoFrom`. Use investigation findings about CellAny vs Cell. - -5. **Completion Pipeline Compatibility**: Confirm that `completeInputsByBalance` chains through `infoFrom` correctly, noting the filter limitation (xUDT only) and the caller-responsibility pattern for receipt/deposit cell discovery. - -6. **Blockers**: List any findings that would make subclassing unviable. If none, state "No blockers identified." - -**## Header Access Pattern (UDT-02)** - -Design the specific pattern: - -1. **API**: `client.getTransactionWithHeader(outPoint.txHash)` -- confirmed from investigation -2. **When**: Only for input cells with outPoint (receipt cells and deposit cells) -3. **What**: Extract `header.dao.ar` for exchange rate computation via `ickbValue()` -4. **Caching**: CCC Client.cache handles repeated calls -- no application-level caching needed -5. **Async flow**: `infoFrom` is already async -- header fetches integrate naturally -6. **Performance**: Few receipt/deposit cells per transaction in practice; caching mitigates repeated fetches in completion loops - -Include a code sketch showing the header fetch pattern within the infoFrom override (referencing the conceptual prototype from 03-RESEARCH.md, updated with any corrections from the investigation). - - - test -f .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && grep -q "## Feasibility Assessment" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && grep -q "## Header Access Pattern" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && echo "PASS" - Verify feasibility assessment addresses all sub-questions and header pattern is specific enough for implementation - - - - Feasibility assessment answers YES/NO/CONDITIONAL with evidence - - All three cell types documented with identification and valuation logic - - Input vs output distinction mechanism documented - - capacityFree access resolved - - Header access pattern fully designed with API, timing, caching, async flow - - Code sketch provided - - - - - Task 2: Write decision and implementation guidance (UDT-03) - .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md - -Append the decision and implementation guidance sections to `03-DECISION.md`: - -**## Decision (UDT-03)** - -State the chosen approach clearly: -- **Chosen**: One of (a) subclass CCC Udt, (b) keep custom UdtHandler interface, (c) hybrid approach -- **Rationale**: Why this approach wins, referencing feasibility assessment findings -- **What it replaces**: Current `UdtHandler` interface + `UdtManager` class in `@ickb/utils` and `IckbUdtManager` in `@ickb/core` -- **What CCC features it gains**: `completeInputsByBalance`, `UdtInfo` accumulator, CCC completion pipeline integration, future upstream improvements -- **What it loses or changes**: Any behavior differences from current implementation - -Per user decisions from CONTEXT.md: -- If subclassing works, that is the preferred path (user is "leaning toward IckbUdt extends udt.Udt") -- If subclassing requires upstream CCC changes, design them generically as "composite UDT" pattern -- Dealbreaker = invasive upstream changes; if blocked, reevaluate WHY and determine minimal CCC changes - -**## Conservation Law Strategy** - -Document how the conservation law `Input UDT + Input Receipts = Output UDT + Input Deposits` is preserved: -- `infoFrom` reports accurate balances with correct sign conventions (deposits negative) -- Enforcement location: on-chain (iCKB Logic script) vs build-time (validation method on IckbUdt) -- Recommendation per CONTEXT.md: start with accurate balance reporting (caller responsibility), add build-time validation later if needed -- Conservation law is NOT embedded in `infoFrom` (balance calculation, not validation) - -**## Cell Discovery vs Balance Calculation Boundary** - -Define the clean separation: -- `infoFrom` responsibility: VALUE cells that are already in the transaction -- Caller responsibility (LogicManager, OwnedOwnerManager): FIND and ADD receipt/deposit cells to the transaction -- `completeInputsByBalance` + `filter`: only finds xUDT cells (this is correct -- receipt/deposit discovery is a separate concern) -- No override of `filter` needed -- callers pre-add special cells, `infoFrom` accurately values them - -**## Implementation Guidance for Phases 4-5** - -Provide actionable guidance: - -Phase 4 (dao/order packages): -- Replace deprecated API calls with `udt.Udt` instance methods -- `udtBalanceFrom` -> `Udt.balanceFromUnsafe()` -- `tx.getInputsUdtBalance()` / `tx.getOutputsUdtBalance()` -> `udt.getInputsInfo()` / `udt.getOutputsInfo()` -- `tx.completeInputsByUdt()` -> `udt.completeInputsByBalance()` -- DaoManager and OrderManager receive a `udt.Udt` instance instead of `UdtHandler` - -Phase 5 (core package): -- Implement `IckbUdt extends udt.Udt` with `infoFrom` override in `packages/core/src/udt.ts` -- Constructor: `code` (OutPoint for xUDT cell dep), `script` (xUDT type script), `logicScript`, `daoManager`, optional `config` -- Override `infoFrom` with three-cell-type logic -- Delete `IckbUdtManager` class from `packages/core/src/udt.ts` -- Delete `UdtHandler` interface and `UdtManager` class from `packages/utils/src/udt.ts` -- Preserve `ickbValue()`, `convert()`, `ickbExchangeRatio()` functions (used by SDK estimate scenarios) -- Update SDK to use `IckbUdt` instance - -**## Upstream CCC Changes** - -Document whether any upstream CCC PRs are needed: -- If `infoFrom` override works without CCC changes: state "No upstream changes required for core feasibility" -- If any issues found: describe minimal, generic changes and assess likely acceptance -- Note: PR #328 (FeePayer) is orthogonal -- `infoFrom` override is compatible with both current and FeePayer architectures - -**## Risks and Mitigations** - -List residual risks with mitigations: -- Filter mismatch for receipt/deposit cell discovery -> mitigation: caller-responsibility pattern -- `DaoManager.isDeposit()` requires `Cell` not `CellAny` -> mitigation: construct `Cell.from(...)` when outPoint present (capacityFree is available on CellAny directly) -- Completion loop performance with header fetches -> mitigation: CCC Client.cache + few cells per tx -- Any other risks identified in the investigation - - - grep -q "## Decision" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && grep -q "## Implementation Guidance" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && grep -q "## Conservation Law Strategy" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && grep -q "## Risks and Mitigations" .planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md && echo "PASS" - Verify decision is clear and unambiguous, implementation guidance is specific enough for Phase 4/5 executors - - - - Decision clearly states chosen approach with rationale - - Conservation law strategy documented - - Cell discovery vs balance calculation boundary defined - - Phase 4 and Phase 5 implementation guidance is specific and actionable - - Upstream CCC changes assessed - - Risks listed with mitigations - - Document is self-contained -- a reader can understand the decision without needing to read the investigation - - - - - - -- `03-DECISION.md` exists with all required sections (Feasibility Assessment, Header Access Pattern, Decision, Conservation Law Strategy, Cell Discovery Boundary, Implementation Guidance, Upstream Changes, Risks) -- The decision is one of the three specified outcomes (a, b, or c) with clear rationale -- Implementation guidance for Phases 4 and 5 is specific enough to plan those phases without revisiting Phase 3 -- All three requirement IDs (UDT-01, UDT-02, UDT-03) have corresponding sections - - - -A Phase 4/5 planner can read `03-DECISION.md` and know exactly: (1) whether to subclass CCC Udt or use a custom approach, (2) how header access works in the override, (3) what classes to create/delete/modify, and (4) how the conservation law is preserved. No re-investigation needed. - - - -After completion, create `.planning/phases/03-ccc-udt-integration-investigation/03-02-SUMMARY.md` - diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-02-SUMMARY.md b/.planning/phases/03-ccc-udt-integration-investigation/03-02-SUMMARY.md deleted file mode 100644 index 62fcdaa..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-02-SUMMARY.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -phase: 03-ccc-udt-integration-investigation -plan: 02 -subsystem: udt -tags: [ccc, udt, subclass, infoFrom, decision-document, header-access, conservation-law] - -# Dependency graph -requires: - - phase: 03-ccc-udt-integration-investigation - plan: 01 - provides: "Source code trace evidence for infoFrom override feasibility, resolved open questions" - - phase: 01-ickb-utils-smarttransaction-removal - provides: "IckbUdtManager with TransactionLike pattern, DaoManager with isDeposit()" - - phase: 02-ccc-utility-adoption - provides: "Clean codebase without deprecated CCC APIs" -provides: - - "Formal decision: IckbUdt extends udt.Udt with infoFrom override" - - "Complete implementation guidance for Phases 4 and 5" - - "Conservation law strategy (accurate balance reporting, caller responsibility)" - - "Cell discovery vs balance calculation boundary definition" - - "Deprecated API replacement table for dao/order/core packages" -affects: [04-deprecated-api-replacement, 05-ickb-udt-implementation, 06-sdk-completion] - -# Tech tracking -tech-stack: - added: [] - patterns: - - "infoFrom override: per-cell balance calculation with outPoint-based input/output discrimination" - - "Three cell types: xUDT (positive), receipt (positive, input only), deposit (negative, input only)" - - "Caller-responsibility pattern for receipt/deposit cell discovery" - -key-files: - created: - - ".planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md" - modified: [] - -key-decisions: - - "Subclass CCC Udt: IckbUdt extends udt.Udt with infoFrom override (option a)" - - "No upstream CCC changes required for IckbUdt subclass" - - "Conservation law: accurate balance reporting only, enforcement is on-chain and optionally build-time later" - - "Cell discovery boundary: infoFrom values cells, callers find and add them" - - "UdtHandler interface and UdtManager class to be deleted in Phase 5" - -patterns-established: - - "Deprecated API replacement: udtBalanceFrom -> balanceFromUnsafe, getInputsUdtBalance -> getInputsInfo, etc." - - "DaoManager/OrderManager receive udt.Udt instance instead of UdtHandler" - -requirements-completed: [UDT-01, UDT-02, UDT-03] - -# Metrics -duration: 4min -completed: 2026-02-24 ---- - -# Phase 3 Plan 2: CCC Udt Decision Document Summary - -**Formal decision document choosing IckbUdt extends udt.Udt with infoFrom override -- feasibility confirmed, header access pattern designed, implementation guidance for Phases 4-5 with deprecated API replacement table and conservation law strategy** - -## Performance - -- **Duration:** 4 min -- **Started:** 2026-02-24T11:27:42Z -- **Completed:** 2026-02-24T11:31:27Z -- **Tasks:** 2 -- **Files modified:** 1 - -## Accomplishments -- Wrote complete decision document with all 8 required sections (Feasibility Assessment, Header Access Pattern, Decision, Conservation Law Strategy, Cell Discovery Boundary, Implementation Guidance, Upstream Changes, Risks) -- Decision: (a) subclass CCC Udt -- IckbUdt extends udt.Udt with infoFrom override, no upstream CCC changes needed -- Conservation law strategy: accurate balance reporting with correct sign conventions (deposits negative), enforcement on-chain only, optional build-time validation later -- Phase 4 guidance: deprecated API replacement table mapping old APIs to new Udt instance methods -- Phase 5 guidance: IckbUdt creation in core package, UdtHandler/UdtManager deletion from utils package, SDK update to use IckbUdt instance -- Six risks documented with concrete mitigations (filter mismatch, isDeposit type, header performance, negative balance, output misidentification, return type changes) - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Write feasibility assessment and header access pattern (UDT-01, UDT-02)** - `681248e` (docs) -2. **Task 2: Write decision and implementation guidance (UDT-03)** - `8daffd7` (docs) - -## Files Created/Modified -- `.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md` - Formal decision document: feasibility YES, header access via getTransactionWithHeader, decision to subclass with infoFrom override, conservation law strategy, cell discovery boundary, implementation guidance for Phases 4-5, upstream assessment, risks and mitigations - -## Decisions Made -- **Subclass CCC Udt (option a):** IckbUdt extends udt.Udt with single infoFrom override handling three cell types (xUDT, receipt, deposit) with outPoint-based input/output discrimination -- **No upstream CCC changes required:** All override points are public with appropriate signatures -- **Conservation law: accurate reporting only:** infoFrom computes balance, does not validate conservation law. On-chain script is authoritative enforcer. Build-time validation can be added later as separate method -- **Cell discovery boundary:** infoFrom values cells already in transaction; LogicManager/OwnedOwnerManager find and add receipt/deposit cells; completeInputsByBalance only finds xUDT cells via filter -- **UdtHandler/UdtManager deletion:** Replaced by udt.Udt type and base class in Phase 5 - -## Deviations from Plan - -None -- plan executed exactly as written. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- Phase 3 investigation is complete -- decision document provides all information needed for Phases 4-5 -- Phase 4 can proceed: deprecated API replacement table specifies exact old->new API mappings for dao and order packages -- Phase 5 can proceed: IckbUdt class specification (constructor, override, deletions, preservations) is fully documented -- No re-investigation needed -- document is self-contained for downstream phase planners - -## Self-Check: PASSED - -- FOUND: `.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md` -- FOUND: `.planning/phases/03-ccc-udt-integration-investigation/03-02-SUMMARY.md` -- FOUND: commit `681248e` -- FOUND: commit `8daffd7` - ---- -*Phase: 03-ccc-udt-integration-investigation* -*Completed: 2026-02-24* diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-CONTEXT.md b/.planning/phases/03-ccc-udt-integration-investigation/03-CONTEXT.md deleted file mode 100644 index 79a0925..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-CONTEXT.md +++ /dev/null @@ -1,75 +0,0 @@ -# Phase 3: CCC Udt Integration Investigation - Context - -**Gathered:** 2026-02-23 -**Status:** Ready for planning - - -## Phase Boundary - -Assess feasibility of subclassing CCC's `udt.Udt` class for iCKB's multi-representation value (xUDT + receipts + deposits). Design the header access pattern. Document the decision. This feeds directly into Phases 4 and 5 — the decision determines how UdtHandler/UdtManager (which remain in `@ickb/utils` with updated signatures after Phase 1) get replaced. - - - - -## Implementation Decisions - -### Evaluation priorities -- CCC alignment is the primary driver — iCKB should feel native to CCC users and benefit from upstream improvements -- Upstream CCC PRs are explicitly on the table if CCC's Udt class needs small, targeted changes to accommodate iCKB's multi-representation value -- No concern about CCC upgrade risk — if we contribute to CCC's Udt, we co-own the design -- PR #328 (FeePayer abstraction by ashuralyk) is the target architecture — investigation should design around it and identify improvements that would better fit iCKB's needs. Now integrated into `forks/ccc` (available at `forks/ccc/packages/core/src/signer/feePayer/`) -- Investigation should cover both cell discovery and balance calculation, not just balance -- Design upstream: if CCC Udt changes are needed, design them generically as a "composite UDT" pattern that benefits other CKB tokens beyond iCKB - -### Subclassing approach -- Leaning toward `IckbUdt extends udt.Udt` — iCKB is fundamentally a UDT, just with extra cell types carrying value -- Two viable override points identified: `getInputsInfo/getOutputsInfo` and `infoFrom` -- `infoFrom` can distinguish between input and output cells by checking outpoint presence (inputs have outpoints, outputs don't) -- Dealbreaker for subclass: if upstream CCC changes needed are too invasive (large, likely-to-be-rejected PRs) -- If subclassing doesn't work, reevaluate WHY it fails and determine what CCC Udt changes would fix it — don't fall back to custom without first trying the upstream path - -### Transaction completion integration -- Standard xUDT token completion must integrate seamlessly (already supported by CCC) -- Accounting for iCKB-specific cells (receipts, deposits) that carry UDT value must also integrate seamlessly into CCC's completion pipeline -- Auto-fetching and auto-adding of receipt/withdrawal-request cells: to be determined — investigate how this fits within PR #328's FeePayer framework (`completeInputs()` with accumulator pattern) - -### Conservation law enforcement -- On-chain iCKB Logic script already enforces `Input UDT + Input Receipts = Output UDT + Input Deposits` at validation time -- Investigation should explore both: (a) IckbUdt subclass enforcing at tx-building time (prevents invalid tx construction), and (b) caller responsibility (IckbUdt only reports accurate balances) -- No risk of funds loss either way — just risk of building invalid transactions that fail on-chain - -### Header access pattern -- Settled: `client.getTransactionWithHeader(outPoint.txHash)` for per-cell header fetching -- CCC is async-native — no concern about async header fetches inside Udt overrides -- Receipt cells store `depositQuantity` and `depositAmount` (not block numbers) — header provides the DAO AR field for exchange rate computation via `ickbValue()` -- Both receipt and deposit cell value calculation need per-cell headers -- Estimate scenarios (SDK.estimate) use pre-computed `ExchangeRatio` from tip header — this is separate from Udt's per-cell balance methods - -### Claude's Discretion -- Technical investigation methodology (which CCC Udt internals to trace first) -- Decision document format and depth of analysis -- Prototype code scope (if any) - - - - -## Specific Ideas - -- `infoFrom` can detect input vs output cells via outpoint presence — investigate this as a cleaner override strategy. Note: STACK.md research incorrectly claimed `CellAnyLike` lacks `outPoint`; it actually has `outPoint?: OutPointLike | null`. `getInputsInfo()` passes `Cell` objects (always have outPoint) to `infoFrom()`, while `getOutputsInfo()` passes `CellAny` from `tx.outputCells` (no outPoint). Both override points are viable. -- PR #328's `completeInputs(tx, filter, accumulator)` pattern (now in `forks/ccc/packages/core/src/signer/feePayer/feePayer.ts`) could be the hook for auto-fetching iCKB receipt/deposit cells during transaction completion. Note: STACK.md research recommended `client.getHeaderByTxHash()` which does not exist in CCC — the correct API is `client.getTransactionWithHeader()` as used in the current codebase. -- The `ickbValue()` function (core/udt.ts:151) and `convert()` function (core/udt.ts:179) are the core exchange rate calculation — these must work within the Udt override context -- Current `IckbUdtManager.getInputsUdtBalance()` (core/udt.ts:66) is the reference implementation for multi-representation balance calculation — three cell types: xUDT cells, receipt cells (type = logicScript), deposit cells (lock = logicScript + isDeposit) - - - - -## Deferred Ideas - -None — discussion stayed within phase scope - - - ---- - -*Phase: 03-ccc-udt-integration-investigation* -*Context gathered: 2026-02-23* diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md b/.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md deleted file mode 100644 index 9bf35b9..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md +++ /dev/null @@ -1,489 +0,0 @@ -# Phase 3: CCC Udt Integration Decision - -**Date:** 2026-02-24 -**Status:** Final -**Requirement IDs:** UDT-01, UDT-02, UDT-03 -**Based on:** 03-01-INVESTIGATION.md (source code trace), 03-RESEARCH.md (architecture analysis) - ---- - -## Feasibility Assessment (UDT-01) - -**Can `IckbUdt extends udt.Udt` override `infoFrom()` to account for receipt cells and deposit cells alongside xUDT cells?** - -**Answer: YES -- feasible with no upstream CCC changes required.** - -### Override Point Selection - -**Selected: `infoFrom`** (not `getInputsInfo`/`getOutputsInfo`) - -Rationale: -- `infoFrom` operates at the per-cell level (`forks/ccc/packages/udt/src/udt/index.ts:624-641`), providing fine-grained control over how each cell contributes to balance -- `getInputsInfo`/`getOutputsInfo` contain input resolution logic (`input.getCell(client)`) and output iteration (`tx.outputCells`) that would need to be duplicated if overridden -- `infoFrom` receives a `client: ccc.Client` parameter (unused in base implementation) that the override needs for header fetches -- `infoFrom` is async, allowing network calls within the override -- A single `infoFrom` override handles both inputs and outputs uniformly -- input/output distinction is via `outPoint` presence - -### Three Cell Types in infoFrom - -**1. xUDT cells (standard UDT balance)** - -- **Identification:** `this.isUdt(cell)` -- checks `cell.cellOutput.type?.eq(this.script)` with full `Script.eq()` (codeHash + hashType + args) and `outputData.length >= 16` bytes (`forks/ccc/packages/udt/src/udt/index.ts:1063-1069`) -- **Balance:** `udt.Udt.balanceFromUnsafe(cell.outputData)` -- reads first 16 bytes as 128-bit LE integer (`index.ts:590-593`). Replaces the manual `ccc.numFromBytes(ccc.bytesFrom(outputData).slice(0, 16))` pattern in current `IckbUdtManager` -- **Applies to:** Both input and output cells -- **Sign:** Positive - -**2. Receipt cells (pending conversion receipts)** - -- **Identification:** `cell.cellOutput.type?.eq(this.logicScript)` -- the iCKB Logic type script identifies receipt cells by type -- **Balance:** `ReceiptData.decode(cell.outputData)` extracts `depositQuantity` and `depositAmount`, then `ickbValue(depositAmount, header) * depositQuantity` computes the iCKB value using the DAO accumulate rate from the block header -- **Applies to:** Input cells only (output receipt cells are newly created receipts from `LogicManager.deposit`, not value carriers) -- **Sign:** Positive -- receipts consumed as inputs contribute iCKB value - -**3. Deposit cells (DAO deposits locked under iCKB Logic)** - -- **Identification:** Two checks: `cell.cellOutput.lock.eq(this.logicScript)` (lock script matches iCKB Logic) AND `this.daoManager.isDeposit(fullCell)` (DAO deposit data pattern). `isDeposit` requires `ccc.Cell` not `CellAny` (see capacityFree resolution below) -- **Balance:** `ickbValue(cell.capacityFree, header)` -- uses unoccupied capacity (not total capacity) with the DAO accumulate rate -- **Applies to:** Input cells only (output deposit cells have DAO type script, not iCKB xUDT type script) -- **Sign:** NEGATIVE -- deposits consumed as inputs subtract from iCKB balance per the conservation law: `Input UDT + Input Receipts = Output UDT + Input Deposits`, rearranged as `Input UDT + Input Receipts - Input Deposits = Output UDT` - -### Input vs Output Distinction - -The `outPoint` property on cells cleanly separates input cells from output cells within `infoFrom`: - -| Source | Type | outPoint | -|--------|------|----------| -| `getInputsInfo` -> `input.getCell(client)` | `Cell` | Always `OutPoint` (from `CellInput.previousOutput`) | -| `getOutputsInfo` -> `tx.outputCells` | `CellAny` | Always `undefined` (no outPoint passed) | -| `completeInputs` accumulator (new cells found) | `Cell` | Always `OutPoint` | - -This is structural, not accidental: `Cell` (which extends `CellAny`) requires `outPoint` in its constructor (`transaction.ts:498`), while `tx.outputCells` yields `CellAny.from({ cellOutput, outputData })` without outPoint (`transaction.ts:1715-1728`). - -The override gates receipt/deposit logic behind `if (!cell.outPoint) continue` -- output cells skip straight to the `isUdt` check for standard xUDT balance. - -### capacityFree Resolution - -`CellAny` has a `capacityFree` getter (`transaction.ts:404-405`): - -```typescript -get capacityFree() { - return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize); -} -``` - -No `Cell` construction is needed for the `ickbValue(cell.capacityFree, header)` computation on deposit cells. - -However, `DaoManager.isDeposit()` (`packages/dao/src/dao.ts:30`) requires `ccc.Cell` (not `CellAny`). Since deposit cells are only relevant as inputs (where `outPoint` is always present), constructing `Cell.from({ outPoint: cell.outPoint!, cellOutput: cell.cellOutput, outputData: cell.outputData })` is safe. The non-null assertion on `outPoint` is valid because deposit detection is gated behind the `if (!cell.outPoint) continue` check. - -### Completion Pipeline Compatibility - -`completeInputsByBalance` chains through `infoFrom` correctly: - -1. `completeInputsByBalance(tx, signer)` calls `getInputsInfo` and `getOutputsInfo` to compute balance deficit -2. Both delegate to `infoFrom` -- the override automatically participates -3. The accumulator in `completeInputs` calls `infoFrom` per new cell found during completion -4. New cells found during completion are `Cell` objects (with `outPoint`), so receipt/deposit logic applies - -**Filter limitation:** `Udt.filter` only matches xUDT cells (by type script + data length >= 16). `completeInputsByBalance` will only find xUDT cells on-chain, not receipt or deposit cells. This is correct by design: - -- Receipt/deposit cell discovery is a separate concern handled by `LogicManager.completeDeposit()` and `OwnedOwnerManager.requestWithdrawal()` -- Callers pre-add receipt/deposit cells to the transaction -- `infoFrom` then accurately values all cells present in the transaction -- `completeInputsByBalance` accounts for the value of pre-added receipt/deposit inputs when calculating how many additional xUDT inputs are needed - -### Blockers - -**No blockers identified.** All override points are public methods with appropriate signatures. No upstream CCC changes are required for core feasibility. - ---- - -## Header Access Pattern (UDT-02) - -### API - -`client.getTransactionWithHeader(outPoint.txHash)` -- confirmed from investigation (`client.ts:631-661`). - -Returns `{ transaction: ClientTransactionResponse, header?: ClientBlockHeader } | undefined` where `header` contains the `dao` field with `ar` (accumulate rate) needed for `ickbValue()`. - -`getCellWithHeader()` is a convenience wrapper that calls `getTransactionWithHeader()` internally -- either works, but `getTransactionWithHeader` is more direct when the txHash is already available from `cell.outPoint.txHash`. - -### When - -Only for input cells with `outPoint` -- specifically receipt cells and deposit cells. Standard xUDT cells do not need header access. - -### What - -The header provides the DAO accumulate rate (`header.dao.ar`) used by `ickbValue()` to compute the exchange rate between CKB capacity and iCKB UDT value: -- Receipt cells: `ickbValue(depositAmount, header) * depositQuantity` -- Deposit cells: `ickbValue(cell.capacityFree, header)` - -### Caching - -CCC's `Client.cache` handles repeated calls transparently: -- First call for a txHash: network fetch + `cache.recordTransactionResponses()` stores result -- Subsequent calls: `cache.getTransactionResponse(txHash)` returns cached response + `cache.hasHeaderConfirmed(header)` confirms header validity -- Multiple cells from the same transaction share one cached header fetch - -No application-level caching is needed. - -### Async Flow - -`infoFrom` is declared `async` in the base class (`Promise` return type). The override uses `await client.getTransactionWithHeader(...)` for receipt and deposit cells. This integrates naturally -- no async wrapper or callback indirection needed. - -### Performance - -- Receipt and deposit cells are typically few per transaction (1-5 in practice) -- Header fetches are small payloads -- CCC caching ensures each unique txHash is fetched at most once per session -- The completion loop in `completeInputsByBalance` re-calls `infoFrom` for each iteration, but the cache prevents redundant network requests - -### Code Sketch - -```typescript -import * as ccc from "@ckb-ccc/core"; -import * as udt from "@ckb-ccc/udt"; -import type { DaoManager } from "@ickb/dao"; -import { ReceiptData, ickbValue } from "./existing-imports.js"; - -class IckbUdt extends udt.Udt { - constructor( - code: ccc.OutPointLike, - script: ccc.ScriptLike, - public readonly logicScript: ccc.Script, - public readonly daoManager: DaoManager, - config?: udt.UdtConfigLike | null, - ) { - super(code, script, config); - } - - override async infoFrom( - client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: udt.UdtInfoLike, - ): Promise { - const info = udt.UdtInfo.from(acc).clone(); - - for (const cellLike of [cells].flat()) { - const cell = ccc.CellAny.from(cellLike); - const { type, lock } = cell.cellOutput; - - // Standard xUDT cell -- applies to both inputs and outputs - if (this.isUdt(cell)) { - info.addAssign({ - balance: udt.Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Receipt and deposit cells are only relevant as inputs (with outPoint) - if (!cell.outPoint) { - continue; - } - - // Receipt cell: type === logicScript - if (type?.eq(this.logicScript)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for receipt cell"); - } - const { depositQuantity, depositAmount } = - ReceiptData.decode(cell.outputData); - info.addAssign({ - balance: - ickbValue(depositAmount, txWithHeader.header) * depositQuantity, - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Deposit cell: lock === logicScript && isDeposit - if (lock.eq(this.logicScript)) { - // Construct Cell for isDeposit() which requires ccc.Cell, not CellAny - const fullCell = ccc.Cell.from({ - outPoint: cell.outPoint, - cellOutput: cell.cellOutput, - outputData: cell.outputData, - }); - if (!this.daoManager.isDeposit(fullCell)) { - continue; - } - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for deposit cell"); - } - // Deposits SUBTRACT from iCKB balance (conservation law) - info.addAssign({ - balance: -ickbValue(cell.capacityFree, txWithHeader.header), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - } - - return info; - } -} -``` - -This code sketch is derived from: -- The base `infoFrom` implementation (`forks/ccc/packages/udt/src/udt/index.ts:624-641`) -- The current `IckbUdtManager.getInputsUdtBalance()` logic (`packages/core/src/udt.ts:66-141`) -- The line-by-line migration mapping from `03-01-INVESTIGATION.md` - ---- - -## Decision (UDT-03) - -### Chosen: (a) Subclass CCC Udt - -**`IckbUdt extends udt.Udt`** with `infoFrom` override is the chosen approach. - -### Rationale - -1. **Feasibility confirmed:** The investigation (03-01-INVESTIGATION.md) traced every CCC Udt method chain end-to-end and confirmed that `infoFrom` is a clean, sufficient override point. No upstream CCC changes are required. - -2. **CCC alignment is the primary driver:** Per CONTEXT.md, iCKB should feel native to CCC users and benefit from upstream improvements. Subclassing `udt.Udt` achieves this -- `IckbUdt` is a first-class CCC UDT that participates in all CCC completion and querying pipelines. - -3. **The override is minimal and clean:** A single method override (`infoFrom`) teaches CCC how to value iCKB's three cell types. No other overrides are needed -- `getInputsInfo`, `getOutputsInfo`, `completeInputsByBalance`, `completeInputs`, `filter` all work as inherited. - -4. **No dealbreakers:** The identified risks (filter mismatch, DaoManager.isDeposit type requirement, async performance) all have clean mitigations (see Risks section). No invasive upstream CCC changes are needed. - -### What It Replaces - -| Current | Replacement | Package | -|---------|-------------|---------| -| `UdtHandler` interface | Deleted (Phase 5) | `@ickb/utils` | -| `UdtManager` class | Deleted (Phase 5) | `@ickb/utils` | -| `IckbUdtManager` class | `IckbUdt extends udt.Udt` (Phase 5) | `@ickb/core` | -| `OrderManager` constructor `udtHandler: UdtHandler` | `udtScript: ccc.Script` (Phase 4) | `@ickb/order` | -| `tx.addCellDeps(this.udtHandler.cellDeps)` in OrderManager | Removed -- caller/CCC Udt handles UDT cellDeps (Phase 4) | `@ickb/order` | -| `tx.getInputsUdtBalance()` (deprecated) | `ickbUdt.getInputsInfo(client, tx)` (Phase 5) | `@ickb/core` | -| `tx.getOutputsUdtBalance()` (deprecated) | `ickbUdt.getOutputsInfo(client, tx)` (Phase 5) | `@ickb/core` | -| `tx.completeInputsByUdt()` (deprecated) | `ickbUdt.completeInputsByBalance(tx, signer)` (Phase 5) | `@ickb/core` | -| `ccc.udtBalanceFrom()` (deprecated) | `udt.Udt.balanceFromUnsafe(outputData)` (Phase 5) | `@ickb/utils`, `@ickb/core` | - -**Note:** `DaoManager` never had a `UdtHandler` parameter -- it only manages DAO operations (deposit, withdrawal request, withdraw). No UDT-related changes needed in `@ickb/dao`. - -### What CCC Features It Gains - -- **`completeInputsByBalance`:** Dual-constraint (balance + capacity) completion with automatic error reporting via `ErrorUdtInsufficientCoin` -- **`UdtInfo` accumulator:** Structured balance + capacity + count tracking via `addAssign`, replacing ad-hoc `[bigint, bigint]` tuples -- **CCC completion pipeline integration:** `IckbUdt` participates in `Transaction.completeBy()` chains alongside other CCC completers -- **Future upstream improvements:** Any improvements to CCC's Udt class (better completion algorithms, new query methods, SSRI integration) automatically apply to `IckbUdt` -- **`getBalanceBurned`:** Inherited method for conservation law verification (inputs - outputs) - -### What It Loses or Changes - -- **`name`, `symbol`, `decimals` as constructor args:** Current `UdtManager` stores these as direct properties. CCC's `Udt` accesses them via SSRI protocol methods (`udt.name()`, `udt.symbol()`, `udt.decimals()`). If direct properties are needed, they can be added as custom fields on `IckbUdt` -- **`cellDeps` array:** Current `UdtHandler.cellDeps` is an explicit `CellDep[]` array. CCC's `Udt` uses `code: OutPoint` which is resolved to cell deps differently. The `Trait.addCellDeps(tx)` method handles this -- **`getInputsUdtBalance` return type:** Changes from `[FixedPoint, FixedPoint]` to `UdtInfo` (which contains `balance`, `capacity`, `count`). Callers must destructure differently -- **Output balance method:** `getOutputsUdtBalance` is replaced by `getOutputsInfo`. Same semantics but returns `UdtInfo` instead of `[FixedPoint, FixedPoint]` - ---- - -## Conservation Law Strategy - -### The Conservation Law - -`Input UDT + Input Receipts = Output UDT + Input Deposits` - -This is enforced on-chain by the iCKB Logic type script. If a transaction violates it, on-chain validation rejects the transaction. There is no risk of funds loss -- only risk of building invalid transactions that fail at submission. - -### How infoFrom Preserves It - -`infoFrom` reports accurate balances with correct sign conventions: - -- **xUDT cells:** Positive balance (both input and output) -- **Receipt cells (input only):** Positive balance -- represents iCKB value the user is redeeming -- **Deposit cells (input only):** NEGATIVE balance -- represents iCKB value the user is providing as CKB deposits - -This means: -- `getInputsInfo` returns: `xUDT balance + receipt value - deposit value` -- `getOutputsInfo` returns: `xUDT balance` (only standard xUDT outputs carry iCKB value) -- `getBalanceBurned` (inherited) = `getInputsInfo.balance - getOutputsInfo.balance` - -When the conservation law holds, `getBalanceBurned` returns zero (or the intended burn amount). - -### Enforcement Location - -- **On-chain (existing):** iCKB Logic script validates the conservation law during CKB transaction verification. This is the authoritative enforcement point and cannot be circumvented. -- **Build-time (future, optional):** A validation method (e.g., `assertConservationLaw(client, tx)`) can be added to `IckbUdt` as a convenience for callers who want early rejection of invalid transactions. This is separate from `infoFrom`. - -### Recommendation - -Per CONTEXT.md: start with accurate balance reporting (caller responsibility). The `infoFrom` override performs balance calculation, not validation. Conservation law enforcement is NOT embedded in `infoFrom` because: - -1. It would conflate calculation with validation -2. It would break the `completeInputsByBalance` loop, which processes partially-constructed transactions that may not yet satisfy the conservation law -3. The on-chain script is the authoritative enforcer -- build-time validation is a convenience, not a requirement - -Build-time validation can be added later as a separate method if needed. The accurate balance reporting from `infoFrom` provides all the data callers need to verify the conservation law themselves. - ---- - -## Cell Discovery vs Balance Calculation Boundary - -### infoFrom Responsibility: VALUE Cells - -`infoFrom` receives cells that are already in the transaction and computes their iCKB value. It does not search for cells on-chain. It does not add cells to the transaction. - -Specifically: -- Cells arrive via `getInputsInfo` (resolved from `tx.inputs`) or `getOutputsInfo` (from `tx.outputCells`) -- `infoFrom` computes `UdtInfo` (balance + capacity + count) for these cells -- The accumulator in `completeInputsByBalance` also feeds cells through `infoFrom` as they are found - -### Caller Responsibility: FIND and ADD Cells - -Receipt and deposit cell discovery is handled by existing manager classes: - -| Cell Type | Discovery Mechanism | Who Calls It | -|-----------|---------------------|--------------| -| xUDT cells | `completeInputsByBalance` via `Udt.filter` | Automatic (CCC completion pipeline) | -| Receipt cells | `LogicManager.completeDeposit()` | Caller (SDK, application code) | -| Deposit cells | `OwnedOwnerManager.requestWithdrawal()`, `LogicManager` | Caller (SDK, application code) | - -### Why No filter Override - -`Udt.filter` is a `ClientIndexerSearchKeyFilter` that only matches xUDT cells (by type script + minimum data length). Receipt and deposit cells have different type scripts and lock scripts -- they cannot be matched by a single filter. - -This is correct by design: -- CCC's `completeInputs` uses a single filter for cell search -- Multi-filter search would require overriding `completeInputsByBalance` and reimplementing dual-constraint optimization -- Receipt/deposit cell discovery involves domain-specific logic (deposit maturity, receipt validity) that belongs in `LogicManager`/`OwnedOwnerManager`, not in `IckbUdt` - -The correct pattern is: -1. Caller adds receipt/deposit cells to the transaction (via LogicManager/OwnedOwnerManager) -2. `infoFrom` accurately values all cells in the transaction (including pre-added receipt/deposit cells) -3. `completeInputsByBalance` determines remaining xUDT deficit and finds additional xUDT cells if needed - ---- - -## Implementation Guidance for Phases 4-5 - -### Phase 4: order Package (UdtHandler Replacement) - -*Updated 2026-02-26 based on Phase 4 discuss-phase. See `04-CONTEXT.md` for full decisions.* - -**Scope clarification:** `@ickb/dao` has no `UdtHandler` references and no deprecated CCC API calls -- it only manages DAO operations. No changes needed. `@ickb/order` uses `UdtHandler` for two things: the UDT type script (`.script`) and cellDeps (`.cellDeps`). Neither package calls deprecated CCC APIs like `udtBalanceFrom` directly -- those calls are in `@ickb/utils`'s `UdtManager` class (deleted in Phase 5). - -**OrderManager constructor change:** -- `udtHandler: UdtHandler` replaced with `udtScript: ccc.Script` -- All 9 `this.udtHandler.script` references become `this.udtScript` -- No `@ckb-ccc/udt` dependency needed -- `ccc.Script` comes from existing `@ckb-ccc/core` - -**UDT cellDeps removal:** -- Remove all `tx.addCellDeps(this.udtHandler.cellDeps)` calls from `mint()`, `addMatch()`, `melt()` -- UDT cellDeps are caller responsibility -- CCC Udt adds its own cellDeps during balance completion -- OrderManager keeps `tx.addCellDeps(this.cellDeps)` for its own order script deps -- Add JSDoc note on affected methods: caller must ensure UDT cellDeps are present - -**Pattern established:** Managers receive plain `ccc.Script` for UDT type identification. The `udt.Udt` instance (including `IckbUdt`) lives at SDK/caller level and handles cellDeps + balance operations externally. This is simpler than initially anticipated. - -### Phase 5: core Package (IckbUdt Implementation) - -*Updated 2026-02-26: Phase 5 discuss-phase expanded scope significantly. See `05-CONTEXT.md` in `.planning/phases/05-ickb-core-udt-refactor/` for authoritative decisions including: individual code deps (not dep group), LogicManager/OwnedOwnerManager udtHandler removal, typeScriptFrom rename, findUdts/UdtCell/ErrorTransactionInsufficientCoin deletion, CCC error adoption. The guidance below is the Phase 3 starting point; 05-CONTEXT.md supersedes it.* - -**Create `IckbUdt extends udt.Udt`** in `packages/core/src/udt.ts`: - -``` -Constructor parameters: - - code: ccc.OutPointLike -- OutPoint for xUDT cell dep - - script: ccc.ScriptLike -- xUDT type script - - logicScript: ccc.Script -- iCKB Logic type script - - daoManager: DaoManager -- for isDeposit() checks - - config?: udt.UdtConfigLike | null -- optional UDT config - -Override: - - infoFrom(client, cells, acc?) -- three-cell-type valuation logic - (see Code Sketch in Header Access Pattern section above) -``` - -**Delete from `packages/core/src/udt.ts`:** -- `IckbUdtManager` class (replaced by `IckbUdt`) -- `getInputsUdtBalance()` override (logic moves to `infoFrom`) -- `getOutputsUdtBalance()` override (base `getOutputsInfo` via `infoFrom` handles this) - -**Delete from `packages/utils/src/udt.ts`:** -- `UdtHandler` interface (replaced by `udt.Udt` type) -- `UdtManager` class (replaced by `udt.Udt` base class) - -**Preserve (do not delete):** -- `ickbValue()` function (`packages/core/src/udt.ts`) -- used within `infoFrom` override and by SDK estimate scenarios -- `convert()` function (`packages/core/src/udt.ts`) -- used by SDK for CKB-to-iCKB conversion -- `ickbExchangeRatio()` function (`packages/core/src/udt.ts`) -- used by SDK estimate scenarios with pre-computed ExchangeRatio from tip header -- `ExchangeRatio` type, `ValueComponents` type -- shared types used across packages -- `ReceiptData` codec -- used within `infoFrom` override for receipt cell decoding - -**Update SDK (`packages/sdk/src/sdk.ts`):** -- Construct `IckbUdt` instance instead of `IckbUdtManager` -- Pass `ickbUdt.script` (plain `ccc.Script`) to `OrderManager` constructor, not the `IckbUdt` instance itself -- `IckbUdt` instance used directly by SDK for balance queries and completion -- not propagated to dao/order managers -- Update balance queries from `[FixedPoint, FixedPoint]` tuple to `UdtInfo` destructuring - ---- - -## Upstream CCC Changes - -**No upstream changes required for core feasibility.** - -The CCC `udt.Udt` class API surface is sufficient for `IckbUdt` subclassing without modification: -- `infoFrom` is a public async method with the right signature -- `isUdt` is a public method for cell type checking -- `balanceFromUnsafe` is a public static method for balance extraction -- `UdtInfo` supports negative balance values via bigint addition -- `Client` provides `getTransactionWithHeader` for header access -- `CellAny` provides `capacityFree` for unoccupied capacity - -**Potential future upstream contributions (non-blocking):** - -If the "composite UDT" pattern (UDT value distributed across multiple cell types) proves useful to other CKB tokens, a generic version could be proposed upstream. This would be a new base class or mixin, not a modification to existing `Udt`. This is not required for iCKB and should only be pursued if clear demand exists from other projects. - -**PR #328 (FeePayer) compatibility:** The `infoFrom` override is compatible with both current and FeePayer architectures. The override operates below the completion routing layer -- whether cells arrive via `Signer.completeInputs` or `FeePayer.completeInputs`, they flow through `getInputsInfo` -> `infoFrom`. No special handling needed for the FeePayer transition. - ---- - -## Risks and Mitigations - -### 1. Filter Mismatch for Receipt/Deposit Cell Discovery - -**Risk:** `completeInputsByBalance` only finds xUDT cells via `Udt.filter`. If callers forget to pre-add receipt/deposit cells, balance calculation will be incomplete. - -**Mitigation:** Caller-responsibility pattern. Document clearly that receipt/deposit cells must be added by `LogicManager`/`OwnedOwnerManager` before calling `completeInputsByBalance`. The SDK already follows this pattern -- `LogicManager.completeDeposit()` and `OwnedOwnerManager.requestWithdrawal()` add these cells. No behavioral change from current implementation. - -### 2. DaoManager.isDeposit() Requires Cell, Not CellAny - -**Risk:** Type mismatch when calling `isDeposit` from within `infoFrom`, which receives `CellAnyLike`. - -**Mitigation:** Construct `Cell.from({ outPoint: cell.outPoint!, cellOutput: cell.cellOutput, outputData: cell.outputData })` when `outPoint` is present. This is safe because deposit cells are only relevant as inputs (which always have `outPoint`). The `capacityFree` computation itself uses `CellAny.capacityFree` directly -- only `isDeposit` needs the `Cell` construction. - -### 3. Completion Loop Performance with Header Fetches - -**Risk:** `infoFrom` makes network calls (header fetches) inside the `completeInputsByBalance` loop. If re-called repeatedly, this could be slow. - -**Mitigation:** CCC `Client.cache` ensures each txHash is fetched at most once per session. Receipt/deposit cells are typically few per transaction (1-5). Multiple cells from the same transaction share one cached header fetch. The base `infoFrom` was already async -- the override does not change the method's contractual behavior, only adds actual async work. - -### 4. UdtInfo.balance Negative Values - -**Risk:** Deposit cells contribute negative balance. If code assumes `UdtInfo.balance >= 0`, it could produce incorrect results. - -**Mitigation:** `UdtInfo.balance` is `ccc.Num` (bigint), which supports negative values. The `completeInputsByBalance` method already checks `info.balance >= ccc.Zero` as its termination condition, correctly handling negative balance contributions. The `addAssign` method does `this.balance += info.balance` which works with negative values. No special handling needed. - -### 5. Output Receipt/Deposit Cell Misidentification - -**Risk:** Output cells that happen to have logic script as type or lock could be misidentified as iCKB value carriers. - -**Mitigation:** The `if (!cell.outPoint) continue` gate prevents any receipt/deposit logic from applying to output cells. Only input cells (with `outPoint`) are evaluated for receipt/deposit value. This is both correct and defensive. - -### 6. Breaking Change in Return Types - -**Risk:** Callers currently expect `[FixedPoint, FixedPoint]` from `getInputsUdtBalance`/`getOutputsUdtBalance`. The new `getInputsInfo`/`getOutputsInfo` return `UdtInfo`. - -**Mitigation:** This is an intentional API change that occurs during Phases 4-5. The migration is straightforward: `const [balance, capacity] = await udtHandler.getInputsUdtBalance(...)` becomes `const { balance, capacity } = await ickbUdt.getInputsInfo(...)`. The `count` field in `UdtInfo` is new and additive. diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-RESEARCH.md b/.planning/phases/03-ccc-udt-integration-investigation/03-RESEARCH.md deleted file mode 100644 index 41bb6a0..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-RESEARCH.md +++ /dev/null @@ -1,440 +0,0 @@ -# Phase 3: CCC Udt Integration Investigation - Research - -**Researched:** 2026-02-23 -**Domain:** CCC UDT subclassing, composite UDT patterns, async header access -**Confidence:** HIGH - - -## User Constraints (from CONTEXT.md) - -### Locked Decisions -- CCC alignment is the primary driver -- iCKB should feel native to CCC users and benefit from upstream improvements -- Upstream CCC PRs are explicitly on the table if CCC's Udt class needs small, targeted changes to accommodate iCKB's multi-representation value -- No concern about CCC upgrade risk -- if we contribute to CCC's Udt, we co-own the design -- PR #328 (FeePayer abstraction by ashuralyk) is the target architecture -- investigation should design around it and identify improvements that would better fit iCKB's needs. Now integrated into `forks/ccc` (available at `forks/ccc/packages/core/src/signer/feePayer/`) -- Investigation should cover both cell discovery and balance calculation, not just balance -- Design upstream: if CCC Udt changes are needed, design them generically as a "composite UDT" pattern that benefits other CKB tokens beyond iCKB -- Leaning toward `IckbUdt extends udt.Udt` -- iCKB is fundamentally a UDT, just with extra cell types carrying value -- Two viable override points identified: `getInputsInfo/getOutputsInfo` and `infoFrom` -- `infoFrom` can distinguish between input and output cells by checking outpoint presence (inputs have outpoints, outputs don't) -- Dealbreaker for subclass: if upstream CCC changes needed are too invasive (large, likely-to-be-rejected PRs) -- If subclassing doesn't work, reevaluate WHY it fails and determine what CCC Udt changes would fix it -- don't fall back to custom without first trying the upstream path -- Standard xUDT token completion must integrate seamlessly (already supported by CCC) -- Accounting for iCKB-specific cells (receipts, deposits) that carry UDT value must also integrate seamlessly into CCC's completion pipeline -- Auto-fetching and auto-adding of receipt/withdrawal-request cells: to be determined -- investigate how this fits within PR #328's FeePayer framework (`completeInputs()` with accumulator pattern) -- On-chain iCKB Logic script already enforces `Input UDT + Input Receipts = Output UDT + Input Deposits` at validation time -- Investigation should explore both: (a) IckbUdt subclass enforcing at tx-building time (prevents invalid tx construction), and (b) caller responsibility (IckbUdt only reports accurate balances) -- No risk of funds loss either way -- just risk of building invalid transactions that fail on-chain -- Settled: `client.getTransactionWithHeader(outPoint.txHash)` for per-cell header fetching -- CCC is async-native -- no concern about async header fetches inside Udt overrides -- Receipt cells store `depositQuantity` and `depositAmount` (not block numbers) -- header provides the DAO AR field for exchange rate computation via `ickbValue()` -- Both receipt and deposit cell value calculation need per-cell headers -- Estimate scenarios (SDK.estimate) use pre-computed `ExchangeRatio` from tip header -- this is separate from Udt's per-cell balance methods - -### Claude's Discretion -- Technical investigation methodology (which CCC Udt internals to trace first) -- Decision document format and depth of analysis -- Prototype code scope (if any) - -### Deferred Ideas (OUT OF SCOPE) -None -- discussion stayed within phase scope - - - -## Phase Requirements - -| ID | Description | Research Support | -|----|-------------|-----------------| -| UDT-01 | Feasibility assessment: can `IckbUdt extends udt.Udt` override `infoFrom()` or `getInputsInfo()`/`getOutputsInfo()` to account for receipt cells and deposit cells alongside xUDT cells | CCC Udt class traced end-to-end; override points mapped; `infoFrom` identified as optimal override; async compatibility confirmed | -| UDT-02 | Header access pattern for receipt value calculation designed -- determine whether `client.getCellWithHeader()`, `client.getTransactionWithHeader()`, or direct CCC client calls are used within the Udt override | `client.getTransactionWithHeader(outPoint.txHash)` confirmed as correct API; `getCellWithHeader` wraps same; header access within async `infoFrom` confirmed viable | -| UDT-03 | Decision documented: subclass CCC `Udt` vs. keep custom `UdtHandler` interface vs. hybrid approach | Full analysis of all three approaches with clear recommendation for subclass approach | - - -## Summary - -This research investigates whether iCKB's multi-representation UDT value (xUDT cells + receipt cells + deposit cells) can be modeled as a subclass of CCC's `udt.Udt` class. The investigation traces CCC's Udt class internals, the current iCKB `IckbUdtManager` implementation, and PR #328's FeePayer architecture. - -**The subclass approach is feasible.** CCC's `udt.Udt` class provides a clean override point via `infoFrom()` that accepts `CellAnyLike | CellAnyLike[]` and a `ccc.Client` parameter. The method is async, allowing header fetches within the override. Input cells passed through `getInputsInfo()` carry `outPoint` (resolved via `CellInput.getCell(client)`), while output cells from `tx.outputCells` do not -- this outPoint presence/absence is the reliable mechanism for distinguishing input vs output cells within `infoFrom()`, which is necessary because receipt and deposit cells only carry iCKB value as inputs (not outputs). The `completeInputsByBalance` method chains through `infoFrom` cleanly, so the override will automatically participate in CCC's completion pipeline. - -**The header access pattern is straightforward.** Receipt and deposit cell value calculation requires the block header of the transaction that created the cell. This is obtained via `client.getTransactionWithHeader(outPoint.txHash)`, which is already used in the current `IckbUdtManager.getInputsUdtBalance()`. Since `infoFrom()` only needs headers for input cells (which have outPoints), and since the method receives a `client` parameter and is async, the pattern integrates naturally. - -**Primary recommendation:** Subclass CCC's `udt.Udt` with `IckbUdt extends udt.Udt`, overriding `infoFrom()` to recognize receipt cells and deposit cells alongside xUDT cells. No upstream CCC changes are required for the core feasibility. PR #328's FeePayer pattern is compatible but orthogonal -- iCKB's `completeInputs` can work with either the current Signer-based approach or future FeePayer-based approach. - -## Standard Stack - -### Core -| Library | Version | Purpose | Why Standard | -|---------|---------|---------|--------------| -| `@ckb-ccc/udt` | workspace (local CCC fork) | Base `Udt` class for subclassing | CCC's official UDT abstraction; `infoFrom` override point | -| `@ckb-ccc/core` | workspace (local CCC fork) | `Transaction`, `Client`, `CellAny`, `CellInput`, `Cell` types | CCC core primitives | -| `@ckb-ccc/ssri` | workspace (local CCC fork) | `ssri.Trait` base class (parent of `Udt`) | SSRI protocol support | - -### Supporting -| Library | Version | Purpose | When to Use | -|---------|---------|---------|-------------| -| `@ickb/dao` | workspace | `DaoManager.isDeposit()` for deposit cell identification | Within `infoFrom` override for deposit cells | -| `@ickb/utils` | workspace | `ExchangeRatio`, `ValueComponents`, `ScriptDeps` types | Type definitions shared across packages | - -### Alternatives Considered -| Instead of | Could Use | Tradeoff | -|------------|-----------|----------| -| `infoFrom` override | `getInputsInfo`/`getOutputsInfo` override | `infoFrom` is more granular (per-cell); `getInputsInfo`/`getOutputsInfo` override would duplicate iteration logic already in base class | -| Subclass `udt.Udt` | Keep `UdtHandler` interface | Custom interface doesn't participate in CCC completion pipeline, loses `completeInputsByBalance`/`completeBy`/etc | - -## Architecture Patterns - -### Pattern 1: `infoFrom` Override for Multi-Representation UDT - -**What:** Override `infoFrom()` in `IckbUdt extends udt.Udt` to recognize three cell types (xUDT, receipt, deposit) and accumulate their iCKB value. - -**When to use:** When a UDT's value is distributed across multiple cell types beyond standard xUDT cells. - -**Key insight:** `infoFrom()` receives `CellAnyLike` objects. Input cells (from `getInputsInfo -> CellInput.getCell()`) have `outPoint` set; output cells (from `getOutputsInfo -> tx.outputCells`) do not. This allows `infoFrom` to: -- For cells with outPoint (inputs): check receipt cells, deposit cells, AND xUDT cells -- For cells without outPoint (outputs): only count standard xUDT cells (receipt/deposit outputs don't carry iCKB value in the same way) - -**Example (conceptual):** -```typescript -// Source: Synthesized from CCC Udt source + iCKB IckbUdtManager source -class IckbUdt extends udt.Udt { - constructor( - code: ccc.OutPointLike, - script: ccc.ScriptLike, - public readonly logicScript: ccc.Script, - public readonly daoManager: DaoManager, - config?: udt.UdtConfigLike | null, - ) { - super(code, script, config); - } - - override async infoFrom( - client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: udt.UdtInfoLike, - ): Promise { - const info = udt.UdtInfo.from(acc).clone(); - - for (const cellLike of [cells].flat()) { - const cell = ccc.CellAny.from(cellLike); - const { type, lock } = cell.cellOutput; - - // Standard xUDT cell -- delegate to base class logic - if (this.isUdt(cell)) { - info.addAssign({ - balance: udt.Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Only input cells (with outPoint) can be receipt/deposit cells - if (!cell.outPoint) { - continue; - } - - // Receipt cell: type === logicScript - if (type?.eq(this.logicScript)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for receipt cell"); - } - const { depositQuantity, depositAmount } = - ReceiptData.decode(cell.outputData); - info.addAssign({ - balance: ickbValue(depositAmount, txWithHeader.header) * depositQuantity, - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Deposit cell: lock === logicScript && isDeposit - if (lock.eq(this.logicScript)) { - // Construct Cell for isDeposit() which requires ccc.Cell, not CellAny - const fullCell = ccc.Cell.from({ outPoint: cell.outPoint, cellOutput: cell.cellOutput, outputData: cell.outputData }); - if (!this.daoManager.isDeposit(fullCell)) { - continue; - } - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for deposit cell"); - } - // Deposits SUBTRACT from iCKB balance (conservation law) - info.addAssign({ - balance: -ickbValue(cell.capacityFree, txWithHeader.header), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - } - - return info; - } -} -``` - -### Pattern 2: Header Access via outPoint.txHash - -**What:** For each receipt or deposit input cell, fetch the block header via `client.getTransactionWithHeader(outPoint.txHash)`, then extract the DAO AR field for exchange rate computation. - -**When to use:** Whenever per-cell iCKB value calculation is needed (not estimate scenarios that use pre-computed ExchangeRatio from tip header). - -**Key details:** -- `client.getTransactionWithHeader()` returns `{ transaction, header? }` where `header` is a `ClientBlockHeader` containing the `dao` field with `ar` (accumulate rate) -- CCC's `Client.cache` transparently caches transaction responses and headers, so repeated calls for the same txHash are cheap -- The method is async, which is compatible with `infoFrom`'s async signature -- `getCellWithHeader()` is a convenience wrapper that calls `getTransactionWithHeader()` internally -- either can be used, but `getTransactionWithHeader` is more direct when you already have the txHash - -### Pattern 3: CCC Completion Pipeline Integration - -**What:** The `IckbUdt` subclass automatically participates in CCC's completion pipeline through inherited methods. - -**How the chain works:** -1. `completeInputsByBalance(tx, signer)` calls `getInputsInfo` and `getOutputsInfo` to compute balance deficit -2. `getInputsInfo` resolves inputs via `CellInput.getCell(client)` then calls `infoFrom(client, inputCells)` -3. `getOutputsInfo` iterates `tx.outputCells` then calls `infoFrom(client, outputCells)` -4. `completeInputs(tx, signer, accumulator, init)` delegates to `tx.completeInputs(signer, this.filter, ...)` -5. The `filter` property on `Udt` controls which cells the signer's `findCellsOnChain` returns - -**Critical detail about `filter`:** The base `Udt` constructor sets `filter` to `{ script: this.script, outputDataLenRange: [16, "0xffffffff"] }` which only finds xUDT cells. The `IckbUdt` subclass should NOT rely on this filter for receipt/deposit cell discovery -- those cells have different type/lock scripts and would not match the xUDT filter. Receipt and deposit cell completion should be handled separately (e.g., by the caller or a dedicated completion method on `IckbUdt`). - -### Anti-Patterns to Avoid -- **Overriding `getInputsInfo`/`getOutputsInfo` directly:** These methods contain resolution logic (resolving `CellInput` to `Cell`, iterating `tx.outputCells`) that would need to be duplicated. Override `infoFrom` instead for cleaner code. -- **Using `infoFrom` for cell discovery:** `infoFrom` is for balance calculation from already-known cells, not for finding cells on-chain. Cell discovery uses `filter` + `completeInputs`. -- **Passing `CellAny` to `DaoManager.isDeposit()`:** `DaoManager.isDeposit()` expects `ccc.Cell`, not `CellAny`. When calling within `infoFrom`, construct `Cell.from({ outPoint, cellOutput, outputData })` from the `CellAny` when `outPoint` is present. This is safe because deposit cells are only relevant as inputs. Note: `capacityFree` is available on `CellAny` directly -- only `isDeposit` requires the `Cell` construction. -- **Ignoring the sign convention for deposits:** In the iCKB conservation law, deposit cells consumed as inputs SUBTRACT from iCKB balance. The current `IckbUdtManager.getInputsUdtBalance()` uses `udtValue - ickbValue(...)` for deposits. The `infoFrom` override must preserve this negative balance contribution. - -## Don't Hand-Roll - -| Problem | Don't Build | Use Instead | Why | -|---------|-------------|-------------|-----| -| UDT balance tracking | Custom balance tracking interface | `udt.UdtInfo` accumulator with `addAssign()` | UdtInfo already handles balance + capacity + count aggregation, tested in CCC | -| Transaction completion | Custom input search + accumulator | `udt.Udt.completeInputsByBalance()` inherited | Handles dual-constraint (balance + capacity) optimization, error reporting | -| Header fetching + caching | Custom header cache | `client.getTransactionWithHeader()` + CCC's `Client.cache` | CCC caches transparently; no need for application-level header caching | -| Cell type checking | Manual script comparison | `this.isUdt(cell)` + `Script.eq()` for logic/deposit checks | Always use full `Script.eq()` (codeHash + hashType + args) per CLAUDE.md | - -**Key insight:** The CCC Udt class already solves the hard problems (completion pipeline, balance/capacity optimization, input deduplication). The iCKB subclass only needs to teach `infoFrom` how to value three cell types instead of one. - -## Common Pitfalls - -### Pitfall 1: Filter Mismatch for Multi-Cell-Type UDTs -**What goes wrong:** The `Udt.filter` only matches xUDT cells (by type script + data length). Calling `completeInputsByBalance` will only find xUDT cells, not receipt or deposit cells. -**Why it happens:** CCC's `completeInputs` uses `Udt.filter` to find cells from the signer. Receipt/deposit cells have different type scripts and lock scripts. -**How to avoid:** Do NOT expect `completeInputsByBalance` to automatically fetch receipt/deposit cells. Either: (a) override `filter` to also include receipt/deposit cells (complex, may not be feasible with single filter), or (b) have the caller pre-add receipt/deposit cells to the transaction before calling completion, or (c) add a custom `completeInputsByBalance` override that performs multiple cell searches. -**Warning signs:** `completeInputsByBalance` reports insufficient balance when receipt/deposit cells exist but are not in the transaction. - -### Pitfall 2: Output Cells vs Input Cells in infoFrom -**What goes wrong:** Applying receipt/deposit valuation logic to output cells, which do not have outPoints and do not carry iCKB value in the same way. -**Why it happens:** `infoFrom` is called for both inputs and outputs. Receipt output cells and deposit output cells exist in transactions but their iCKB value semantics differ from inputs. -**How to avoid:** Check `cell.outPoint` presence before applying receipt/deposit logic. Only input cells (with outPoint) contribute receipt/deposit value. Output receipt cells are new receipts being created (handled by LogicManager.deposit), not value carriers for balance purposes. -**Warning signs:** Double-counting or sign errors in balance calculation. - -### Pitfall 3: Deposit Cell Balance Sign Convention -**What goes wrong:** Treating deposit cell iCKB value as positive when it should be negative (conservation law: consuming a deposit reduces the iCKB balance the user must provide). -**Why it happens:** The conservation law is `Input UDT + Input Receipts = Output UDT + Input Deposits`. Rearranging for net balance: `Input UDT + Input Receipts - Input Deposits = Output UDT`. So deposits consumed as inputs have negative iCKB balance contribution. -**How to avoid:** In `infoFrom`, deposit cells use `balance: -ickbValue(...)` (negative). The current `IckbUdtManager.getInputsUdtBalance()` already uses this convention. -**Warning signs:** Transactions fail on-chain with conservation law violation. - -### Pitfall 4: Capacity Calculation for Deposit Cells -**What goes wrong:** Using `cell.cellOutput.capacity` directly instead of `cell.capacityFree` (unoccupied capacity) for deposit cell iCKB value. -**Why it happens:** The iCKB exchange rate applies to unoccupied capacity, not total capacity. Deposit cells have 82 CKB occupied capacity. -**How to avoid:** Use `cell.capacityFree` (which is `capacity - fixedPointFrom(occupiedSize)`) when computing `ickbValue()` for deposit cells. `CellAny` has `capacityFree` (transaction.ts:404-405), so this works directly within `infoFrom`. -**Warning signs:** Slight over-valuation of deposit cells leading to invalid transactions. - -### Pitfall 5: Async infoFrom and CCC's Completion Loop -**What goes wrong:** The `infoFrom` override makes network calls (header fetches) inside the completion loop, potentially causing performance issues. -**Why it happens:** `completeInputsByBalance` calls `getInputsInfo` which calls `infoFrom` for each input. If there are many receipt/deposit cells, each triggers a header fetch. -**How to avoid:** CCC's `Client.cache` mitigates this -- repeated calls for the same txHash are served from cache. For the initial fetch, the overhead is inherent and acceptable because: (a) receipt/deposit cells are typically few per transaction, and (b) headers are small payloads. No custom optimization needed. -**Warning signs:** Slow transaction building with many receipt/deposit inputs (unlikely in practice). - -## Code Examples - -### Current IckbUdtManager Balance Calculation (Reference) -```typescript -// Source: packages/core/src/udt.ts lines 66-141 -// This is the existing implementation that the IckbUdt subclass must replicate -override async getInputsUdtBalance( - client: ccc.Client, - txLike: ccc.TransactionLike, -): Promise<[ccc.FixedPoint, ccc.FixedPoint]> { - const tx = ccc.Transaction.from(txLike); - return ccc.reduceAsync( - tx.inputs, - async (acc, input) => { - await input.completeExtraInfos(client); - const { previousOutput: outPoint, cellOutput, outputData } = input; - if (!cellOutput || !outputData) throw new Error("Unable to complete input"); - const { type, lock } = cellOutput; - if (!type) return acc; - const cell = new ccc.Cell(outPoint, cellOutput, outputData); - const [udtValue, capacity] = acc; - - // xUDT cell - if (this.isUdt(cell)) { - return [udtValue + ccc.numFromBytes(ccc.bytesFrom(outputData).slice(0, 16)), capacity + cellOutput.capacity]; - } - // Receipt cell - if (this.logicScript.eq(type)) { - const txWithHeader = await client.getTransactionWithHeader(outPoint.txHash); - if (!txWithHeader?.header) throw new Error("Header not found"); - const { depositQuantity, depositAmount } = ReceiptData.decode(outputData); - return [udtValue + ickbValue(depositAmount, txWithHeader.header) * depositQuantity, capacity + cellOutput.capacity]; - } - // Deposit cell - if (this.logicScript.eq(lock) && this.daoManager.isDeposit(cell)) { - const txWithHeader = await client.getTransactionWithHeader(outPoint.txHash); - if (!txWithHeader?.header) throw new Error("Header not found"); - return [udtValue - ickbValue(cell.capacityFree, txWithHeader.header), capacity + cellOutput.capacity]; - } - return acc; - }, - [0n, 0n], - ); -} -``` - -### CCC Udt.infoFrom Base Implementation (Override Target) -```typescript -// Source: forks/ccc/packages/udt/src/udt/index.ts lines 624-641 -async infoFrom( - _client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: UdtInfoLike, -): Promise { - return [cells].flat().reduce((acc, cellLike) => { - const cell = ccc.CellAny.from(cellLike); - if (!this.isUdt(cell)) { - return acc; - } - return acc.addAssign({ - balance: Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - }, UdtInfo.from(acc).clone()); -} -``` - -### CCC getInputsInfo Chain (How Input Cells Reach infoFrom) -```typescript -// Source: forks/ccc/packages/udt/src/udt/index.ts lines 1099-1108 -async getInputsInfo(client: ccc.Client, txLike: ccc.TransactionLike): Promise { - const tx = ccc.Transaction.from(txLike); - const inputCells = await Promise.all( - tx.inputs.map((input) => input.getCell(client)), - // getCell returns Cell.from({ outPoint: input.previousOutput, cellOutput, outputData }) - // These Cell objects ALWAYS have outPoint set - ); - return this.infoFrom(client, inputCells); -} - -// Source: forks/ccc/packages/udt/src/udt/index.ts lines 1178-1184 -async getOutputsInfo(client: ccc.Client, txLike: ccc.TransactionLike): Promise { - const tx = ccc.Transaction.from(txLike); - return this.infoFrom(client, Array.from(tx.outputCells)); - // tx.outputCells yields CellAny WITHOUT outPoint -} -``` - -### CellAny OutPoint Presence (Input vs Output Detection) -```typescript -// Source: forks/ccc/packages/core/src/ckb/transaction.ts lines 313-318, 331-348 -type CellAnyLike = { - outPoint?: OutPointLike | null; // present for inputs, absent for outputs - previousOutput?: OutPointLike | null; - cellOutput: CellOutputLike; - outputData?: HexLike | null; -}; - -class CellAny { - public outPoint: OutPoint | undefined; // undefined for output cells - get capacityFree() { return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize); } - // ... -} -``` - -### PR #328 FeePayer.completeInputs Signature -```typescript -// Source: forks/ccc/packages/core/src/signer/feePayer/feePayer.ts lines 26-39 -abstract completeInputs( - tx: Transaction, - filter: ClientCollectableSearchKeyFilterLike, - accumulator: (acc: T, v: Cell, i: number, array: Cell[]) => Promise | T | undefined, - init: T, -): Promise<{ - addedCount: number; - accumulated?: T; -}>; -``` - -## State of the Art - -| Old Approach | Current Approach | When Changed | Impact | -|--------------|------------------|--------------|--------| -| `UdtHandler` interface + `UdtManager` class (iCKB custom) | CCC `udt.Udt` class with `infoFrom`/`getInputsInfo`/`getOutputsInfo` | CCC `@ckb-ccc/udt` package | Udt class provides completion pipeline; UdtHandler/UdtManager don't | -| `ccc.udtBalanceFrom()` (deprecated) | `udt.Udt.balanceFromUnsafe(outputData)` | Current CCC | Old API deprecated, new one in Udt class | -| `tx.completeInputsByUdt()` (deprecated) | `udt.completeInputsByBalance(tx, signer)` | Current CCC | Old on Transaction, new on Udt instance | -| `tx.getInputsUdtBalance()` / `tx.getOutputsUdtBalance()` (deprecated) | `udt.getInputsInfo(client, tx)` / `udt.getOutputsInfo(client, tx)` | Current CCC | New methods return UdtInfo (balance + capacity + count) | -| PR #328 FeePayer Udt (uses deprecated APIs) | Current CCC Udt (uses `infoFrom`) | Integrated into forks/ccc | PR #328's Udt is simpler, still uses old deprecated APIs; current CCC Udt is more complete | - -**Deprecated/outdated:** -- `ccc.udtBalanceFrom()`: Replaced by `udt.Udt.balanceFromUnsafe()` -- `tx.completeInputsByUdt()`: Replaced by `udt.Udt.completeInputsByBalance()` -- `tx.getInputsUdtBalance()` / `tx.getOutputsUdtBalance()`: Replaced by `udt.Udt.getInputsInfo()` / `udt.Udt.getOutputsInfo()` -- PR #328 FeePayer branch's Udt class: Uses deprecated APIs above; the current CCC Udt class (which we work with via forks/ccc) is more advanced - -## Open Questions - -1. **Receipt/Deposit Cell Discovery in completeInputsByBalance** - - What we know: `completeInputsByBalance` uses `this.filter` to find cells, which only matches xUDT cells by type script. Receipt and deposit cells have different scripts and won't be found. - - What's unclear: Should `IckbUdt` override `completeInputsByBalance` to also search for receipt/deposit cells? Or should receipt/deposit cells be pre-added to the transaction by the caller (as the current `LogicManager.completeDeposit` and `OwnedOwnerManager.requestWithdrawal` do)? - - Recommendation: **Caller responsibility.** The current pattern already has `LogicManager` and `OwnedOwnerManager` handling receipt/deposit cell discovery and addition. `IckbUdt.infoFrom` should accurately VALUE these cells when they appear in the transaction, but should NOT be responsible for FINDING them. This keeps the subclass clean and avoids fighting CCC's single-filter design. The `completeInputsByBalance` method then correctly accounts for receipt/deposit value that the caller has already added. - -2. **`capacityFree` on CellAny vs Cell** - - What we know: `ickbValue()` for deposit cells uses `cell.capacityFree` (unoccupied capacity). - - **Resolved:** `CellAny` has `capacityFree` getter (transaction.ts:404-405): `get capacityFree() { return this.cellOutput.capacity - fixedPointFrom(this.occupiedSize); }`. No need to construct a `Cell` -- `CellAny.from(cellLike).capacityFree` works directly in `infoFrom`. - - Note: `DaoManager.isDeposit()` still requires `ccc.Cell` (not `CellAny`). For deposit cells (which have `outPoint`), construct `Cell.from({ outPoint, cellOutput, outputData })` for the `isDeposit` call only. - -3. **PR #328 FeePayer Integration** - - What we know: PR #328 abstracts `completeInputs` into `FeePayer.completeInputs(tx, filter, accumulator, init)`. The current CCC Udt's `completeInputs` delegates to `tx.completeInputs(from, this.filter, ...)` which delegates to `from.completeInputs(...)` (Signer). PR #328 changes this to go through `FeePayer.completeInputs`. - - What's unclear: Whether IckbUdt needs any special handling for the FeePayer transition. - - Recommendation: **No special handling needed.** The `infoFrom` override is at a level below the completion plumbing. Whether `completeInputs` goes through Signer (current) or FeePayer (PR #328), the cells still flow through `getInputsInfo` -> `infoFrom`. The override is compatible with both architectures. - -4. **Conservation Law Enforcement in IckbUdt** - - What we know: On-chain iCKB Logic script enforces `Input UDT + Input Receipts = Output UDT + Input Deposits`. User decision says to explore both enforcement-at-build-time and caller-responsibility. - - What's unclear: The exact enforcement mechanism if implemented at build time. - - Recommendation: Start with **accurate balance reporting only** (caller responsibility). `infoFrom` correctly values all three cell types with proper sign conventions. A `getBalanceBurned()` call (inherited from base `Udt`) can then be used by callers to verify the conservation law before submitting. Enforcement at build time can be added later as a validation method if needed, but should not be embedded in `infoFrom` (which is a balance calculation method, not a validation method). - -## Sources - -### Primary (HIGH confidence) -- `forks/ccc/packages/udt/src/udt/index.ts` -- CCC Udt class source, `infoFrom`, `getInputsInfo`, `getOutputsInfo`, `completeInputsByBalance` full implementation -- `forks/ccc/packages/core/src/ckb/transaction.ts` -- `CellAny`, `CellAnyLike`, `Cell`, `CellInput.getCell()`, `outputCells` getter -- `forks/ccc/packages/core/src/client/client.ts` -- `getTransactionWithHeader()`, `getCellWithHeader()` implementations -- `packages/core/src/udt.ts` -- Current `IckbUdtManager`, `ickbValue()`, `convert()`, `ickbExchangeRatio()` -- `packages/utils/src/udt.ts` -- Current `UdtHandler` interface, `UdtManager` base class -- `packages/core/src/logic.ts` -- `LogicManager`, receipt/deposit identification -- `packages/core/src/cells.ts` -- `ReceiptCell`, `IckbDepositCell`, `receiptCellFrom` header access pattern -- `forks/ccc/packages/core/src/signer/feePayer/feePayer.ts` -- PR #328 FeePayer abstract class (now integrated into forks/ccc) - -### Secondary (MEDIUM confidence) -- None -- all findings verified from source code - -### Tertiary (LOW confidence) -- None - -## Metadata - -**Confidence breakdown:** -- Standard stack: HIGH -- all source code directly inspected in the workspace -- Architecture: HIGH -- override points verified by tracing full method chains in CCC source -- Pitfalls: HIGH -- derived from comparing current iCKB implementation with CCC Udt API surface; sign conventions and cell type distinctions verified from existing code - -**Research date:** 2026-02-23 -**Valid until:** Stable -- CCC Udt class API is mature; valid until major CCC refactor diff --git a/.planning/phases/03-ccc-udt-integration-investigation/03-VERIFICATION.md b/.planning/phases/03-ccc-udt-integration-investigation/03-VERIFICATION.md deleted file mode 100644 index e96e8ae..0000000 --- a/.planning/phases/03-ccc-udt-integration-investigation/03-VERIFICATION.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -phase: 03-ccc-udt-integration-investigation -verified: 2026-02-24T12:00:00Z -status: passed -score: 6/6 must-haves verified -re_verification: false ---- - -# Phase 3: CCC Udt Integration Investigation Verification Report - -**Phase Goal:** Clear, documented decision on whether IckbUdt should extend CCC's `udt.Udt` class for iCKB's multi-representation value (xUDT + receipts + deposits), with the header access pattern designed. This decision determines the replacement for UdtHandler/UdtManager (which remain in `@ickb/utils` with updated signatures after Phase 1). -**Verified:** 2026-02-24T12:00:00Z -**Status:** passed -**Re-verification:** No — initial verification - ---- - -## Goal Achievement - -### Observable Truths - -Success criteria are drawn from ROADMAP.md Phase 3 and the `must_haves` frontmatter of 03-02-PLAN.md. - -| # | Truth | Status | Evidence | -|---|-------|--------|----------| -| 1 | A written feasibility assessment exists answering whether `IckbUdt extends udt.Udt` can override `infoFrom()` to account for receipt cells and deposit cells alongside xUDT cells without breaking CCC method chains | VERIFIED | `03-DECISION.md` "## Feasibility Assessment" section, 481-line document with YES answer, six sub-sections covering override point, three cell types, input/output distinction, capacityFree resolution, completion pipeline compatibility, and blockers | -| 2 | The header access pattern for receipt value calculation is designed and documented, specifying which CCC client API is used within the Udt override | VERIFIED | `03-DECISION.md` "## Header Access Pattern" section documents `client.getTransactionWithHeader(outPoint.txHash)` with confirmed line reference `client.ts:631-661`, caching behavior, async flow, and code sketch | -| 3 | A decision document exists with one of three outcomes (subclass/custom/hybrid) and rationale | VERIFIED | `03-DECISION.md` "## Decision" section explicitly states "Chosen: (a) Subclass CCC Udt" with four numbered rationale points, replacement table, gained features, and changed behaviors | -| 4 | The conservation law preservation strategy is documented (sign conventions and cell type handling) | VERIFIED | `03-DECISION.md` "## Conservation Law Strategy" section documents sign conventions (deposits negative), enforcement location (on-chain authoritative, optional build-time later), and `getBalanceBurned` inherited usage | -| 5 | The cell discovery vs balance calculation boundary is defined | VERIFIED | `03-DECISION.md` "## Cell Discovery vs Balance Calculation Boundary" section defines boundary: `infoFrom` values cells present in transaction; LogicManager/OwnedOwnerManager find and add receipt/deposit cells; rationale for no filter override provided | -| 6 | The decision document provides sufficient detail for Phase 4 and Phase 5 implementers to proceed without ambiguity | VERIFIED | `03-DECISION.md` "## Implementation Guidance for Phases 4-5" contains explicit deprecated API replacement table (4 mappings), manager constructor changes, Phase 5 constructor spec, deletion list, preservation list, and SDK update guidance | - -**Score:** 6/6 truths verified - ---- - -### Required Artifacts - -| Artifact | Expected | Status | Details | -|----------|----------|--------|---------| -| `.planning/phases/03-ccc-udt-integration-investigation/03-01-INVESTIGATION.md` | Detailed source code trace findings with exact line references and code snippets | VERIFIED | 717 lines; contains all 8 required sections; 24 concrete `file:line` references to CCC source; line-by-line mapping from `IckbUdtManager.getInputsUdtBalance` to `infoFrom` override | -| `.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md` | Formal decision document covering UDT-01, UDT-02, UDT-03 | VERIFIED | 481 lines; all 8 required sections present; "## Decision" section with explicit "Chosen: (a) Subclass CCC Udt"; 2 TypeScript code blocks; 39 references to `infoFrom`; implementation guidance for both phases | - -Both artifacts pass all three verification levels: -- **Level 1 (Exists):** Both files present on disk -- **Level 2 (Substantive):** Both exceed 400 lines, contain required section headings, include concrete code references -- **Level 3 (Wired):** DECISION.md is derived from INVESTIGATION.md (03-02-SUMMARY.md documents this chain); investigation is summarized in 03-01-SUMMARY.md which feeds 03-02 plan context - ---- - -### Key Link Verification - -| From | To | Via | Status | Details | -|------|----|-----|--------|---------| -| `03-01-INVESTIGATION.md` | `03-DECISION.md` | Investigation findings cited in decision (line references, code snippets in DECISION match investigation source) | WIRED | DECISION.md cites `index.ts:624-641`, `transaction.ts:404-405`, `client.ts:631-661` matching investigation findings; 03-02-PLAN.md explicitly depends on 03-01 | -| `03-DECISION.md` | ROADMAP.md Phase 4 and Phase 5 approach | "Decision outcome determines Phase 4 and Phase 5 approach" | WIRED | DECISION.md "## Implementation Guidance" contains explicit Phase 4 (dao/order API replacement table) and Phase 5 (IckbUdt creation, deletion list, SDK update) guidance; ROADMAP.md Phase 4/5 both reference "based on Phase 3 findings" | - ---- - -### Requirements Coverage - -| Requirement | Source Plan | Description | Status | Evidence | -|-------------|-------------|-------------|--------|----------| -| UDT-01 | 03-01-PLAN.md, 03-02-PLAN.md | Feasibility assessment: can `IckbUdt extends udt.Udt` override `infoFrom()` or `getInputsInfo()`/`getOutputsInfo()` to account for receipt and deposit cells alongside xUDT cells | SATISFIED | `03-DECISION.md` "## Feasibility Assessment" answers YES with source code evidence from investigation; REQUIREMENTS.md marks `[x]` complete | -| UDT-02 | 03-01-PLAN.md, 03-02-PLAN.md | Header access pattern for receipt value calculation is designed -- which CCC client API is used within the Udt override | SATISFIED | `03-DECISION.md` "## Header Access Pattern" documents `client.getTransactionWithHeader()` confirmed at `client.ts:631-661`; caching, async flow, code sketch included; REQUIREMENTS.md marks `[x]` complete | -| UDT-03 | 03-02-PLAN.md | Decision documented: subclass CCC Udt vs. keep custom UdtHandler interface vs. hybrid approach | SATISFIED | `03-DECISION.md` "## Decision" states "(a) Subclass CCC Udt" with rationale; REQUIREMENTS.md marks `[x]` complete | - -No orphaned requirements: REQUIREMENTS.md maps only UDT-01, UDT-02, UDT-03 to Phase 3. All three claimed by plans. All three present in DECISION.md with dedicated sections. - ---- - -### Anti-Patterns Found - -No modified source code files in this phase — it is a documentation-only investigation phase. Anti-pattern scanning is not applicable. Files created: `03-01-INVESTIGATION.md`, `03-DECISION.md`, `03-01-SUMMARY.md`, `03-02-SUMMARY.md`. - -No TODO/FIXME/placeholder patterns in any created documentation files. - ---- - -### Human Verification Required - -None. This phase produces documentation artifacts (a decision document and an investigation document). All goal criteria are verifiable by inspecting file existence, section headings, content specificity, and commit hash validity — all automated checks pass. - ---- - -### Commits Verified - -All commits documented in summaries confirmed to exist in git history: -- `b2827e5` — Investigation document (03-01) — EXISTS -- `681248e` — Decision document feasibility and header sections (03-02 Task 1) — EXISTS -- `8daffd7` — Decision document decision and implementation guidance (03-02 Task 2) — EXISTS - ---- - -## Summary - -Phase 3 goal is achieved. The phase produced two substantive documentation artifacts: - -**`03-01-INVESTIGATION.md`** (717 lines) traces every CCC Udt method chain (`infoFrom`, `getInputsInfo`, `getOutputsInfo`, `completeInputsByBalance`, `completeInputs`) with 24 concrete source file:line references. It resolves all 4 open questions from 03-RESEARCH.md with code evidence and provides a line-by-line mapping from the current `IckbUdtManager.getInputsUdtBalance` to the planned `IckbUdt.infoFrom` override. - -**`03-DECISION.md`** (481 lines) contains all 8 required sections. It answers the phase's three requirements: -- UDT-01: Feasibility YES, `infoFrom` is the sole override point, no upstream CCC changes required -- UDT-02: `client.getTransactionWithHeader(outPoint.txHash)` is the header access API, with caching handled by CCC `Client.cache` -- UDT-03: Decision is (a) subclass CCC Udt — `IckbUdt extends udt.Udt` with `infoFrom` override - -The document is self-contained: a Phase 4 or Phase 5 implementer can read it and know exactly what classes to create, delete, and modify, what APIs replace what, and how the conservation law is preserved. No re-investigation is needed. - ---- - -_Verified: 2026-02-24T12:00:00Z_ -_Verifier: AI Coworker (gsd-verifier)_ diff --git a/.planning/phases/04-deprecated-ccc-api-replacement/04-01-PLAN.md b/.planning/phases/04-deprecated-ccc-api-replacement/04-01-PLAN.md deleted file mode 100644 index fcb42b1..0000000 --- a/.planning/phases/04-deprecated-ccc-api-replacement/04-01-PLAN.md +++ /dev/null @@ -1,214 +0,0 @@ ---- -phase: 04-deprecated-ccc-api-replacement -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - packages/order/src/order.ts - - packages/sdk/src/constants.ts -autonomous: true -requirements: - - SMTX-05 - -must_haves: - truths: - - "OrderManager constructor accepts udtScript: ccc.Script as its third parameter" - - "OrderManager methods do not add UDT cellDeps to transactions" - - "@ickb/order does not import UdtHandler from @ickb/utils" - - "SDK constructs OrderManager with ickbUdt.script (a ccc.Script), not the full IckbUdtManager instance" - - "pnpm check:full passes with zero errors" - artifacts: - - path: "packages/order/src/order.ts" - provides: "OrderManager with udtScript: ccc.Script parameter, no UDT cellDeps" - contains: "public readonly udtScript: ccc.Script" - - path: "packages/sdk/src/constants.ts" - provides: "SDK caller passing ickbUdt.script to OrderManager" - contains: "ickbUdt.script" - key_links: - - from: "packages/sdk/src/constants.ts" - to: "packages/order/src/order.ts" - via: "OrderManager constructor call" - pattern: "new OrderManager\\(.*ickbUdt\\.script\\)" - - from: "packages/order/src/order.ts" - to: "@ckb-ccc/core" - via: "ccc.Script type for udtScript" - pattern: "udtScript: ccc\\.Script" ---- - - -Replace UdtHandler dependency in @ickb/order with plain ccc.Script; remove UDT cellDeps management from OrderManager; update SDK caller site. - -Purpose: OrderManager only needs the UDT type script for cell identification (type script matching, output cell construction). The full UdtHandler interface with balance/completion methods is unnecessary coupling. UDT cellDeps management is moved to the caller/CCC Udt during balance completion, aligning with CCC's completion pipeline pattern. - -Output: Modified order.ts and constants.ts; verified @ickb/dao is already clean; verified Phase 3 decision doc already corrected. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/04-deprecated-ccc-api-replacement/04-CONTEXT.md -@.planning/phases/04-deprecated-ccc-api-replacement/04-RESEARCH.md - - - - -From packages/order/src/order.ts (BEFORE -- current state): -```typescript -import { type UdtHandler } from "@ickb/utils"; - -export class OrderManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly udtHandler: UdtHandler, // CHANGE THIS - ) {} -} -``` - -9 udtHandler references to replace (verified line-by-line): -- Line 7: `type UdtHandler,` in import -> REMOVE from import -- Line 22: JSDoc `@param udtHandler` -> `@param udtScript` -- Line 27: constructor `public readonly udtHandler: UdtHandler` -> `public readonly udtScript: ccc.Script` -- Line 42: `this.udtHandler.script` -> `this.udtScript` (isOrder) -- Line 190: `tx.addCellDeps(this.udtHandler.cellDeps)` -> DELETE LINE (mint) -- Line 196: `this.udtHandler.script` -> `this.udtScript` (mint output) -- Line 229: `tx.addCellDeps(this.udtHandler.cellDeps)` -> DELETE LINE (addMatch) -- Line 236: `this.udtHandler.script` -> `this.udtScript` (addMatch output) -- Line 519: `tx.addCellDeps(this.udtHandler.cellDeps)` -> DELETE LINE (melt) -- Line 635: `this.udtHandler.script` -> `this.udtScript` (findSimpleOrders) - -From packages/sdk/src/constants.ts line 78: -```typescript -const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt); -// ickbUdt is IckbUdtManager which implements UdtHandler -// Change to: ickbUdt.script -``` - -From @ickb/utils (UdtHandler interface -- reference only, NOT modified): -```typescript -export interface UdtHandler extends ScriptDeps { - script: ccc.Script; - cellDeps: ccc.CellDep[]; -} -``` - - - - - - - Task 1: Replace UdtHandler with udtScript in OrderManager and update SDK caller - packages/order/src/order.ts, packages/sdk/src/constants.ts - -In `packages/order/src/order.ts`: - -1. Remove `type UdtHandler,` from the `@ickb/utils` import statement (line 7). Keep all other imports (`BufferedGenerator`, `defaultFindCellsLimit`, `ExchangeRatio`, `ScriptDeps`, `ValueComponents`). - -2. Update JSDoc on line 22: change `@param udtHandler - The handler for UDT (User Defined Token).` to `@param udtScript - The UDT (User Defined Token) type script.` - -3. Update constructor parameter on line 27: change `public readonly udtHandler: UdtHandler,` to `public readonly udtScript: ccc.Script,` - -4. In `isOrder()` (line 42): change `this.udtHandler.script` to `this.udtScript` - -5. In `mint()`: - - DELETE line 190: `tx.addCellDeps(this.udtHandler.cellDeps);` - - Change line 196: `type: this.udtHandler.script,` to `type: this.udtScript,` - - Add JSDoc `@remarks` to mint()'s existing JSDoc block (after the existing content, before `@param`): `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via CCC Udt balance completion).` - -6. In `addMatch()`: - - DELETE line 229: `tx.addCellDeps(this.udtHandler.cellDeps);` - - Change line 236: `type: this.udtHandler.script,` to `type: this.udtScript,` - - Add JSDoc `@remarks` to addMatch()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via CCC Udt balance completion).` - -7. In `melt()`: - - DELETE line 519: `tx.addCellDeps(this.udtHandler.cellDeps);` - - Add JSDoc `@remarks` to melt()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via CCC Udt balance completion).` - -8. In `findSimpleOrders()` (line 635): change `script: this.udtHandler.script,` to `script: this.udtScript,` - -In `packages/sdk/src/constants.ts`: - -9. Change line 78 from: - `const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt);` - to: - `const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script);` - -Apply changes top-to-bottom within each file to avoid line number drift issues. - - - cd /workspaces/stack && pnpm check:full - - - - OrderManager constructor parameter is `udtScript: ccc.Script` (not `udtHandler: UdtHandler`) - - All 4 `.script` accesses simplified from `this.udtHandler.script` to `this.udtScript` - - All 3 `tx.addCellDeps(this.udtHandler.cellDeps)` lines deleted from mint/addMatch/melt - - `UdtHandler` no longer appears in @ickb/order imports - - JSDoc @remarks added to mint(), addMatch(), melt() about caller cellDeps responsibility - - SDK passes `ickbUdt.script` to OrderManager constructor - - `pnpm check:full` passes - - - - - Task 2: Verify @ickb/dao and Phase 3 decision doc are already clean - - -Verify (grep-based, no changes expected): - -1. Confirm @ickb/dao has no UdtHandler references: - `grep -r "UdtHandler\|udtHandler" packages/dao/src/` should return no matches. - -2. Confirm @ickb/dao has no deprecated CCC API calls: - `grep -r "udtBalanceFrom\|getInputsUdtBalance\|getOutputsUdtBalance\|completeInputsByUdt" packages/dao/src/` should return no matches. - -3. Confirm Phase 3 decision doc `03-DECISION.md` lines 369-388 already contain the correct Phase 4 guidance (updated 2026-02-26 in commit c7ba503): - - States DaoManager never had UdtHandler - - States OrderManager gets `udtScript: ccc.Script` - - States UDT cellDeps removed from OrderManager - If content is correct, no changes needed (verification only). - -4. Confirm @ickb/order no longer imports UdtHandler after Task 1: - `grep -r "UdtHandler" packages/order/src/` should return no matches. - -All four checks must pass. If any check fails, investigate and fix. These are expected to all pass (dao was always clean, decision doc was pre-corrected, order was cleaned in Task 1). - - - cd /workspaces/stack && grep -r "UdtHandler\|udtHandler" packages/dao/src/ packages/order/src/ ; echo "exit: $?" - - - - @ickb/dao confirmed clean: no UdtHandler references, no deprecated CCC API calls - - Phase 3 decision doc verified correct (no changes needed) - - @ickb/order confirmed clean: no remaining UdtHandler references after Task 1 - - - - - - -1. `pnpm check:full` passes -- all 5 library packages compile with zero type errors -2. `grep -r "UdtHandler\|udtHandler" packages/order/src/ packages/dao/src/` returns no matches -3. `grep -r "udtBalanceFrom\|getInputsUdtBalance\|getOutputsUdtBalance\|completeInputsByUdt" packages/dao/src/ packages/order/src/` returns no matches -4. `grep "udtScript: ccc.Script" packages/order/src/order.ts` confirms new parameter -5. `grep "ickbUdt.script" packages/sdk/src/constants.ts` confirms SDK caller update - - - -- OrderManager uses `udtScript: ccc.Script` instead of `udtHandler: UdtHandler` -- No UDT cellDeps added by OrderManager (3 lines deleted) -- @ickb/order has zero imports of UdtHandler -- SDK constructs OrderManager with `ickbUdt.script` -- @ickb/dao verified clean (no changes needed) -- Phase 3 decision doc verified correct (no changes needed) -- `pnpm check:full` passes - - - -After completion, create `.planning/phases/04-deprecated-ccc-api-replacement/04-01-SUMMARY.md` - diff --git a/.planning/phases/04-deprecated-ccc-api-replacement/04-01-SUMMARY.md b/.planning/phases/04-deprecated-ccc-api-replacement/04-01-SUMMARY.md deleted file mode 100644 index 8db6f50..0000000 --- a/.planning/phases/04-deprecated-ccc-api-replacement/04-01-SUMMARY.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -phase: 04-deprecated-ccc-api-replacement -plan: 01 -subsystem: api -tags: [ccc, udt, order, refactor, decoupling] - -# Dependency graph -requires: - - phase: 03-ccc-udt-integration-investigation - provides: Decision to use ccc.Script for UDT type identification in managers -provides: - - OrderManager with udtScript: ccc.Script parameter (no UdtHandler dependency) - - UDT cellDeps removed from OrderManager (caller/CCC Udt responsibility) - - SDK caller site updated to pass ickbUdt.script -affects: [05-remaining-ccc-migration] - -# Tech tracking -tech-stack: - added: [] - patterns: [managers-receive-plain-script, caller-manages-udt-celldeps] - -key-files: - created: [] - modified: - - packages/order/src/order.ts - - packages/sdk/src/constants.ts - -key-decisions: - - "OrderManager receives ccc.Script (not udt.Udt) -- simpler than Phase 3 anticipated" - - "UDT cellDeps are caller responsibility -- documented via JSDoc @remarks on mint/addMatch/melt" - -patterns-established: - - "Manager plain-script pattern: managers receive plain ccc.Script for UDT type identification, udt.Udt instance lives at SDK/caller level" - - "Caller cellDeps pattern: transaction-building methods do not add UDT cellDeps; callers ensure them via CCC Udt balance completion" - -requirements-completed: [SMTX-05] - -# Metrics -duration: 4min -completed: 2026-02-26 ---- - -# Phase 4 Plan 01: Replace UdtHandler with udtScript Summary - -**OrderManager decoupled from UdtHandler: constructor takes ccc.Script, UDT cellDeps removed, SDK caller updated** - -## Performance - -- **Duration:** 4 min -- **Started:** 2026-02-26T11:11:01Z -- **Completed:** 2026-02-26T11:14:56Z -- **Tasks:** 2 -- **Files modified:** 2 - -## Accomplishments -- OrderManager constructor parameter changed from `udtHandler: UdtHandler` to `udtScript: ccc.Script` -- All 4 `this.udtHandler.script` accesses simplified to `this.udtScript` -- All 3 `tx.addCellDeps(this.udtHandler.cellDeps)` lines deleted from mint/addMatch/melt -- `UdtHandler` import removed from @ickb/order -- JSDoc `@remarks` added to mint(), addMatch(), melt() documenting caller cellDeps responsibility -- SDK caller updated to pass `ickbUdt.script` instead of `ickbUdt` -- @ickb/dao verified clean (no UdtHandler, no deprecated CCC APIs) -- Phase 3 decision doc verified correct (no changes needed) - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Replace UdtHandler with udtScript in OrderManager and update SDK caller** - `9e6e3d8` (feat) -2. **Task 2: Verify @ickb/dao and Phase 3 decision doc are already clean** - no commit (verification-only, no changes) - -## Files Created/Modified -- `packages/order/src/order.ts` - OrderManager: udtScript parameter, removed UDT cellDeps, updated JSDoc -- `packages/sdk/src/constants.ts` - SDK getConfig: passes ickbUdt.script to OrderManager constructor - -## Decisions Made -- OrderManager receives `ccc.Script` directly (not `udt.Udt`) -- simpler pattern than Phase 3 anticipated, since OrderManager only needs the type script for cell identification -- UDT cellDeps responsibility moved to caller, documented via JSDoc `@remarks` on affected methods - -## Deviations from Plan - -None - plan executed exactly as written. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- Phase 4 complete (single plan phase) -- Pattern established: managers receive plain `ccc.Script`, `udt.Udt` lives at caller level -- Ready for Phase 5: IckbUdt implementation in @ickb/core, UdtHandler/UdtManager deletion in @ickb/utils - -## Self-Check: PASSED - -- FOUND: packages/order/src/order.ts -- FOUND: packages/sdk/src/constants.ts -- FOUND: 04-01-SUMMARY.md -- FOUND: commit 9e6e3d8 - ---- -*Phase: 04-deprecated-ccc-api-replacement* -*Completed: 2026-02-26* diff --git a/.planning/phases/04-deprecated-ccc-api-replacement/04-CONTEXT.md b/.planning/phases/04-deprecated-ccc-api-replacement/04-CONTEXT.md deleted file mode 100644 index 8aaea70..0000000 --- a/.planning/phases/04-deprecated-ccc-api-replacement/04-CONTEXT.md +++ /dev/null @@ -1,65 +0,0 @@ -# Phase 4: Deprecated CCC API Replacement - Context - -**Gathered:** 2026-02-26 -**Status:** Ready for planning - - -## Phase Boundary - -Replace `UdtHandler` dependency in `@ickb/order` with a plain `ccc.Script` parameter; remove UDT cellDeps management from OrderManager (caller/CCC Udt handles it externally during balance completion); verify `@ickb/dao` has no deprecated CCC API calls (it doesn't); correct Phase 3 decision document inaccuracies. UdtHandler/UdtManager deletion happens in Phase 5, not here. - - - - -## Implementation Decisions - -### OrderManager parameter design -- Replace `udtHandler: UdtHandler` constructor parameter with `udtScript: ccc.Script` -- OrderManager only needs the UDT type script -- not the full `udt.Udt` class or `UdtHandler` interface -- No new `@ckb-ccc/udt` dependency needed on `@ickb/order` -- `ccc.Script` comes from existing `@ckb-ccc/core` -- Strict parameter swap: all 9 `this.udtHandler.script` references become `this.udtScript` -- Keep `ScriptDeps` interface on OrderManager (still describes its own script + cellDeps) -- Keep `ExchangeRatio`, `ValueComponents`, and other `@ickb/utils` imports unchanged -- Update JSDoc `@param` for the renamed parameter -- Do NOT audit unrelated imports -- only replace UdtHandler - -### CellDeps migration pattern -- Remove all `tx.addCellDeps(this.udtHandler.cellDeps)` calls from `mint()`, `addMatch()`, and `melt()` -- UDT cellDeps are now caller responsibility -- CCC Udt adds its own cellDeps during balance completion -- OrderManager still adds its own cellDeps via `tx.addCellDeps(this.cellDeps)` (order script deps) -- Add JSDoc note on `mint()`, `addMatch()`, `melt()`: caller must ensure UDT cellDeps are added to the transaction -- `ScriptDeps` interface unchanged -- still correctly describes OrderManager's own deps - -### Phase scope boundaries -- `@ickb/dao`: No changes needed. Already clean (no UdtHandler, no deprecated CCC APIs). Verified by `pnpm check:full` -- `@ickb/order`: Replace UdtHandler with udtScript, remove UDT cellDeps calls -- `@ickb/utils`: Leave UdtManager's 3 deprecated `ccc.udtBalanceFrom()` calls for Phase 5 (UdtManager is being deleted there) -- Update roadmap success criteria to reflect actual changes (UdtHandler replacement, not deprecated API removal in dao/order) -- Correct Phase 3 decision document: rewrite the "Implementation Guidance for Phase 4" section to match actual decisions (DaoManager never had UdtHandler; OrderManager gets ccc.Script not udt.Udt) -- Import audit of remaining @ickb/utils imports: out of scope - -### Claude's Discretion -- Exact JSDoc wording for the cellDeps caller-responsibility notes -- Whether to update the Phase 3 decision's replacement mapping table or restructure the section - - - - -## Specific Ideas - -- The pattern established here is simpler than Phase 3 anticipated: managers get `ccc.Script`, not `udt.Udt` instances. The `udt.Udt` instance (including `IckbUdt`) lives at the SDK/caller level, not in dao/order managers. -- Phase 5 should note that dao/order managers don't need `udt.Udt` propagated to them -- the Udt instance handles completion externally. - - - - -## Deferred Ideas - -None -- discussion stayed within phase scope. - - - ---- - -*Phase: 04-deprecated-ccc-api-replacement* -*Context gathered: 2026-02-26* diff --git a/.planning/phases/04-deprecated-ccc-api-replacement/04-RESEARCH.md b/.planning/phases/04-deprecated-ccc-api-replacement/04-RESEARCH.md deleted file mode 100644 index a64a6f0..0000000 --- a/.planning/phases/04-deprecated-ccc-api-replacement/04-RESEARCH.md +++ /dev/null @@ -1,365 +0,0 @@ -# Phase 4: Deprecated CCC API Replacement - Research - -**Researched:** 2026-02-26 -**Domain:** CKB UDT handler interface replacement in @ickb/order package -**Confidence:** HIGH - -## Summary - -Phase 4 is a focused refactoring of `OrderManager` in `@ickb/order` to replace the `UdtHandler` interface dependency with a plain `ccc.Script` parameter. The scope is narrow and well-defined: 9 lines in one file (`order.ts`) need modification, one SDK caller site needs updating, and `@ickb/dao` needs verification (already confirmed clean). The Phase 3 decision document was already corrected in commit `c7ba503` during the discuss-phase -- this should be verified rather than re-done. - -This is a straightforward mechanical refactoring with no new dependencies, no architecture decisions, and no deprecated API calls to replace in the target packages. The pattern established here (managers receive `ccc.Script`, not `udt.Udt`) is the foundation that Phase 5 builds upon. - -**Primary recommendation:** Single plan covering OrderManager parameter swap, cellDeps removal, SDK caller update, dao verification, and Phase 3 doc verification. All changes are interdependent and should be in one atomic commit. - - -## User Constraints (from CONTEXT.md) - -### Locked Decisions -- Replace `udtHandler: UdtHandler` constructor parameter with `udtScript: ccc.Script` -- OrderManager only needs the UDT type script -- not the full `udt.Udt` class or `UdtHandler` interface -- No new `@ckb-ccc/udt` dependency needed on `@ickb/order` -- `ccc.Script` comes from existing `@ckb-ccc/core` -- Strict parameter swap: all 9 `this.udtHandler.script` references become `this.udtScript` -- Keep `ScriptDeps` interface on OrderManager (still describes its own script + cellDeps) -- Keep `ExchangeRatio`, `ValueComponents`, and other `@ickb/utils` imports unchanged -- Update JSDoc `@param` for the renamed parameter -- Do NOT audit unrelated imports -- only replace UdtHandler -- Remove all `tx.addCellDeps(this.udtHandler.cellDeps)` calls from `mint()`, `addMatch()`, and `melt()` -- UDT cellDeps are now caller responsibility -- CCC Udt adds its own cellDeps during balance completion -- OrderManager still adds its own cellDeps via `tx.addCellDeps(this.cellDeps)` (order script deps) -- Add JSDoc note on `mint()`, `addMatch()`, `melt()`: caller must ensure UDT cellDeps are added to the transaction -- `ScriptDeps` interface unchanged -- still correctly describes OrderManager's own deps -- `@ickb/dao`: No changes needed. Already clean (no UdtHandler, no deprecated CCC APIs). Verified by `pnpm check:full` -- `@ickb/order`: Replace UdtHandler with udtScript, remove UDT cellDeps calls -- `@ickb/utils`: Leave UdtManager's 3 deprecated `ccc.udtBalanceFrom()` calls for Phase 5 (UdtManager is being deleted there) -- Update roadmap success criteria to reflect actual changes (UdtHandler replacement, not deprecated API removal in dao/order) -- Correct Phase 3 decision document: rewrite the "Implementation Guidance for Phase 4" section to match actual decisions -- Import audit of remaining @ickb/utils imports: out of scope - -### Claude's Discretion -- Exact JSDoc wording for the cellDeps caller-responsibility notes -- Whether to update the Phase 3 decision's replacement mapping table or restructure the section - -### Deferred Ideas (OUT OF SCOPE) -None -- discussion stayed within phase scope. - - - -## Phase Requirements - -| ID | Description | Research Support | -|----|-------------|-----------------| -| SMTX-05 | UDT handler registration (`addUdtHandlers()`) is replaced by direct `Udt` instance usage or standalone utility functions | Phase 4 portion: OrderManager.udtHandler replaced with udtScript: ccc.Script; UDT cellDeps removed from OrderManager methods. The `UdtHandler` import is removed from @ickb/order. Full deletion of UdtHandler/UdtManager deferred to Phase 5. | - - -## Standard Stack - -### Core -| Library | Version | Purpose | Why Standard | -|---------|---------|---------|--------------| -| `@ckb-ccc/core` | Already in package.json (catalog:) | Provides `ccc.Script`, `ccc.CellDep`, `ccc.Transaction`, `ccc.TransactionLike` | Core CCC types -- `ccc.Script` is the replacement for `UdtHandler.script` | -| `@ickb/utils` | workspace:* | Provides `ScriptDeps`, `ExchangeRatio`, `ValueComponents`, `BufferedGenerator`, `defaultFindCellsLimit` | Shared types/utilities -- UdtHandler import removed but other imports remain | - -### Supporting -No new libraries needed. No dependency changes to package.json. - -### Alternatives Considered -| Instead of | Could Use | Tradeoff | -|------------|-----------|----------| -| `ccc.Script` | `udt.Udt` instance | Over-engineered -- OrderManager only needs type script for cell identification, not balance/completion capabilities. Locked decision: `ccc.Script`. | - -**Installation:** -No installation needed. All required types already available from existing `@ckb-ccc/core` dependency. - -## Architecture Patterns - -### Current Structure (Before Phase 4) -``` -packages/order/src/ - order.ts # OrderManager class -- 9 udtHandler references to change - cells.ts # OrderCell, MasterCell, OrderGroup -- no changes needed - entities.ts # OrderData, Info, Ratio -- no changes needed - index.ts # barrel export -- no changes needed -``` - -### Pattern 1: Manager Receives Plain Script -**What:** OrderManager constructor takes `udtScript: ccc.Script` instead of `udtHandler: UdtHandler`. The manager only uses the UDT type script for cell identification (type script matching in `isOrder`, `findSimpleOrders`, output cell construction in `mint`, `addMatch`). -**When to use:** When a manager needs to identify cells by type script but does not need balance calculation, completion, or cellDeps management for that script. -**Example:** -```typescript -// Before (current): -constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly udtHandler: UdtHandler, -) {} - -// After (Phase 4): -constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly udtScript: ccc.Script, -) {} -``` - -### Pattern 2: Caller-Managed CellDeps -**What:** OrderManager no longer adds UDT cellDeps to transactions. The UDT's cellDeps are the caller's responsibility -- CCC's `udt.Udt` adds its own cellDeps during balance completion (`Trait.addCellDeps(tx)`), so OrderManager does not need to duplicate this. -**When to use:** When a component constructs partial transactions that are completed by a higher-level orchestrator (SDK) using CCC's completion pipeline. -**Example:** -```typescript -// Before (current) -- mint(): -tx.addCellDeps(this.cellDeps); -tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE this line - -// After (Phase 4) -- mint(): -tx.addCellDeps(this.cellDeps); -// UDT cellDeps handled by caller/CCC Udt during balance completion -``` - -### Pattern 3: SDK Caller Passes Script -**What:** The SDK's `getConfig()` constructs `OrderManager` with `ickbUdt.script` (a `ccc.Script`) instead of the full `IckbUdtManager` instance. -**Example:** -```typescript -// Before (packages/sdk/src/constants.ts:78): -const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt); - -// After: -const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script); -``` - -### Anti-Patterns to Avoid -- **Passing full UdtHandler/UdtManager to managers that only need Script:** Over-couples components. Managers should receive the minimum data they need. -- **Adding UDT cellDeps in multiple places:** Creates duplication and ordering issues. CCC's completion pipeline handles cellDeps via `Trait.addCellDeps`. -- **Changing cells.ts or entities.ts:** These files have no UdtHandler dependency. Do not modify them. - -## Don't Hand-Roll - -| Problem | Don't Build | Use Instead | Why | -|---------|-------------|-------------|-----| -| UDT type script identification | Custom `UdtHandler` interface with `.script` property | Plain `ccc.Script` parameter | `ccc.Script` already has `.eq()` for comparison -- no wrapper needed | -| UDT cellDeps management in partial transactions | `tx.addCellDeps(udtHandler.cellDeps)` in every method | CCC's `udt.Udt.addCellDeps(tx)` during completion | CCC manages its own deps -- managers should not duplicate | - -**Key insight:** OrderManager's relationship to UDT is purely type-script-based identification. It checks "is this cell a UDT cell?" and "construct a UDT-typed output cell". Both operations only need `ccc.Script`, not the full `UdtHandler` interface with balance/completion methods. - -## Common Pitfalls - -### Pitfall 1: Forgetting the SDK Caller Site -**What goes wrong:** Changing `OrderManager` constructor but not updating `packages/sdk/src/constants.ts:78` where `new OrderManager(d.order.script, d.order.cellDeps, ickbUdt)` passes the full `IckbUdtManager` instance. -**Why it happens:** The change is in `@ickb/order` but the caller is in `@ickb/sdk`, a different package. -**How to avoid:** Update `constants.ts:78` to pass `ickbUdt.script` instead of `ickbUdt`. TypeScript will catch this at compile time since `IckbUdtManager` is not assignable to `ccc.Script`. -**Warning signs:** Type error during `pnpm check:full` -- "Argument of type 'IckbUdtManager' is not assignable to parameter of type 'Script'". - -### Pitfall 2: Missing the Import Removal -**What goes wrong:** Removing all `udtHandler` usage but leaving `type UdtHandler` in the import statement on line 7 of `order.ts`. -**Why it happens:** Mechanical replacement of property accesses misses the import declaration. -**How to avoid:** After replacing all 9 references, remove `type UdtHandler` from the import statement. The linter will also catch unused imports. -**Warning signs:** `@typescript-eslint/no-unused-vars` or `no-unused-imports` lint error. - -### Pitfall 3: Incorrect Reference Count -**What goes wrong:** Thinking there are only 4 `.script` references when there are actually 9 total `udtHandler` mentions (including JSDoc, constructor parameter, `.script` accesses, and `.cellDeps` accesses). -**Why it happens:** Counting only one property pattern instead of all mentions. -**How to avoid:** The 9 references break down as: - - Line 22: JSDoc `@param udtHandler` -> update to `@param udtScript` - - Line 27: Constructor `public readonly udtHandler: UdtHandler` -> `public readonly udtScript: ccc.Script` - - Line 42: `this.udtHandler.script` -> `this.udtScript` (isOrder) - - Line 190: `this.udtHandler.cellDeps` -> DELETE LINE (mint) - - Line 196: `this.udtHandler.script` -> `this.udtScript` (mint output) - - Line 229: `this.udtHandler.cellDeps` -> DELETE LINE (addMatch) - - Line 236: `this.udtHandler.script` -> `this.udtScript` (addMatch output) - - Line 519: `this.udtHandler.cellDeps` -> DELETE LINE (melt) - - Line 635: `this.udtHandler.script` -> `this.udtScript` (findSimpleOrders filter) - -### Pitfall 4: Phase 3 Decision Doc Re-correction -**What goes wrong:** Attempting to re-correct the Phase 3 decision document when it was already corrected in commit `c7ba503` during the discuss-phase. -**Why it happens:** The roadmap success criterion #5 says to correct it, but the correction was applied proactively. -**How to avoid:** Verify the current content of `03-DECISION.md` lines 369-388 already contains the correct Phase 4 guidance (updated 2026-02-26). If correct, document verification rather than making changes. -**Warning signs:** If lines 369-388 mention "DaoManager UdtHandler replacement" or "udt.Udt instance" for OrderManager, correction is still needed. Current content correctly says neither. - -### Pitfall 5: Breaking @ickb/core Callers of UdtHandler -**What goes wrong:** Modifying `UdtHandler` interface or `UdtManager` class in `@ickb/utils` during Phase 4. -**Why it happens:** Desire to clean up the source of `UdtHandler`. -**How to avoid:** Phase 4 only touches `@ickb/order` (consumer) and `@ickb/sdk` (caller). The `UdtHandler` interface and `UdtManager` class in `@ickb/utils` remain untouched until Phase 5. `@ickb/core`'s `LogicManager` and `OwnedOwnerManager` still use `udtHandler: UdtHandler` -- they are out of scope. - -## Code Examples - -Verified patterns from codebase investigation: - -### OrderManager Constructor Change -```typescript -// packages/order/src/order.ts -// Source: Verified from current codebase line 16-28 - -import { ccc } from "@ckb-ccc/core"; -import { - BufferedGenerator, - defaultFindCellsLimit, - type ExchangeRatio, - type ScriptDeps, - // NOTE: UdtHandler import REMOVED - type ValueComponents, -} from "@ickb/utils"; - -export class OrderManager implements ScriptDeps { - /** - * Creates an instance of OrderManager. - * - * @param script - The order script. - * @param cellDeps - The cell dependencies for the order. - * @param udtScript - The UDT (User Defined Token) type script. - */ - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly udtScript: ccc.Script, - ) {} -``` - -### isOrder Method Change -```typescript -// packages/order/src/order.ts -// Source: Verified from current codebase line 39-44 - -isOrder(cell: ccc.Cell): boolean { - return ( - cell.cellOutput.lock.eq(this.script) && - Boolean(cell.cellOutput.type?.eq(this.udtScript)) // was: this.udtHandler.script - ); -} -``` - -### mint() cellDeps Removal and JSDoc Update -```typescript -// packages/order/src/order.ts -// Source: Verified from current codebase lines 154-209 - -/** - * Mints a new order cell and appends it to the transaction. - * - * ...existing JSDoc... - * - * @remarks Caller must ensure UDT cellDeps are added to the transaction - * (e.g., via CCC Udt balance completion). - */ -mint( - txLike: ccc.TransactionLike, - lock: ccc.Script, - info: InfoLike, - amounts: ValueComponents, -): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - // ...data creation... - - tx.addCellDeps(this.cellDeps); - // REMOVED: tx.addCellDeps(this.udtHandler.cellDeps); - - const position = tx.addOutput( - { - lock: this.script, - type: this.udtScript, // was: this.udtHandler.script - }, - data.toBytes(), - ); - // ...rest unchanged... -} -``` - -### SDK Caller Update -```typescript -// packages/sdk/src/constants.ts -// Source: Verified from current codebase line 78 - -// Before: -const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt); - -// After: -const order = new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script); -``` - -## State of the Art - -| Old Approach | Current Approach | When Changed | Impact | -|--------------|------------------|--------------|--------| -| `UdtHandler` interface with script + cellDeps + balance methods | Plain `ccc.Script` for type identification; `udt.Udt` for cellDeps/balance at SDK level | Phase 4 (this phase) | Managers are simpler; UDT completion logic centralized in CCC | -| `tx.addCellDeps(udtHandler.cellDeps)` in every method | CCC Udt handles its own cellDeps during completion | Phase 4 (this phase) | No duplicate cellDep management; aligns with CCC patterns | - -**Deprecated/outdated:** -- `UdtHandler` interface: Still exists in `@ickb/utils` -- deleted in Phase 5. Phase 4 only removes its usage from `@ickb/order`. -- `UdtManager` class: Still exists in `@ickb/utils` -- deleted in Phase 5. Not touched in Phase 4. - -## Precise Change Map - -### File: `packages/order/src/order.ts` - -| Line | Current | After | Category | -|------|---------|-------|----------| -| 7 | `type UdtHandler,` | (remove from import) | Import cleanup | -| 22 | `@param udtHandler - The handler for UDT` | `@param udtScript - The UDT type script.` | JSDoc | -| 27 | `public readonly udtHandler: UdtHandler,` | `public readonly udtScript: ccc.Script,` | Constructor | -| 42 | `this.udtHandler.script` | `this.udtScript` | isOrder() | -| 190 | `tx.addCellDeps(this.udtHandler.cellDeps);` | (remove line) | mint() cellDeps | -| 196 | `type: this.udtHandler.script,` | `type: this.udtScript,` | mint() output | -| 229 | `tx.addCellDeps(this.udtHandler.cellDeps);` | (remove line) | addMatch() cellDeps | -| 236 | `type: this.udtHandler.script,` | `type: this.udtScript,` | addMatch() output | -| 519 | `tx.addCellDeps(this.udtHandler.cellDeps);` | (remove line) | melt() cellDeps | -| 635 | `script: this.udtHandler.script,` | `script: this.udtScript,` | findSimpleOrders() | - -Additionally: JSDoc `@remarks` notes on `mint()`, `addMatch()`, `melt()` for caller responsibility. - -### File: `packages/sdk/src/constants.ts` - -| Line | Current | After | Category | -|------|---------|-------|----------| -| 78 | `new OrderManager(d.order.script, d.order.cellDeps, ickbUdt)` | `new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script)` | Caller update | - -### Files NOT Changed (verified clean) -- `packages/dao/src/dao.ts` -- No UdtHandler, no deprecated CCC APIs -- `packages/dao/src/cells.ts` -- No UdtHandler, no deprecated CCC APIs -- `packages/dao/src/index.ts` -- No UdtHandler -- `packages/order/src/cells.ts` -- No UdtHandler -- `packages/order/src/entities.ts` -- No UdtHandler -- `packages/order/src/index.ts` -- No UdtHandler -- `packages/utils/src/udt.ts` -- UdtHandler/UdtManager remain (Phase 5 scope) -- `packages/core/src/logic.ts` -- udtHandler references remain (Phase 5 scope) -- `packages/core/src/owned_owner.ts` -- udtHandler references remain (Phase 5 scope) -- `packages/core/src/udt.ts` -- IckbUdtManager remains (Phase 5 scope) - -### Phase 3 Decision Doc Verification -- `03-DECISION.md` lines 369-388: Already corrected in commit `c7ba503` (2026-02-26) -- Content now correctly states: DaoManager never had UdtHandler; OrderManager gets `udtScript: ccc.Script`; UDT cellDeps removed from OrderManager -- Action: Verify content is correct, no additional changes needed - -## Open Questions - -1. **Line numbers may shift after edits** - - What we know: Line numbers referenced above are from the current file state - - What's unclear: Removing 3 cellDeps lines shifts all subsequent line numbers - - Recommendation: Apply changes top-to-bottom or use pattern matching rather than absolute line numbers - -2. **SDK type return change** - - What we know: `getConfig()` return type includes `order: OrderManager`. After this change, `OrderManager.udtScript` is `ccc.Script` instead of `OrderManager.udtHandler` being `UdtHandler` - - What's unclear: Whether any SDK callers access `order.udtHandler` directly - - Recommendation: Search for `order.udtHandler` usage in SDK tests/apps before finalizing. None found in library packages. - -## Sources - -### Primary (HIGH confidence) -- Direct codebase inspection of `packages/order/src/order.ts` (all 9 udtHandler references verified line by line) -- Direct codebase inspection of `packages/dao/src/dao.ts`, `packages/dao/src/cells.ts` (confirmed zero UdtHandler/deprecated API usage) -- Direct codebase inspection of `packages/sdk/src/constants.ts:78` (single OrderManager construction site in libraries) -- Git log of `03-DECISION.md` (correction already in commit `c7ba503`) - -### Secondary (MEDIUM confidence) -- Phase 3 decision document `03-DECISION.md` sections on Phase 4 guidance (verified current and accurate) - -### Tertiary (LOW confidence) -- None -- all findings verified from codebase - -## Metadata - -**Confidence breakdown:** -- Standard stack: HIGH - No new dependencies, all types from existing `@ckb-ccc/core` -- Architecture: HIGH - Mechanical refactoring with exact change map verified line-by-line -- Pitfalls: HIGH - All pitfalls discovered from codebase analysis (cross-package caller, import cleanup, reference count) - -**Research date:** 2026-02-26 -**Valid until:** Indefinite -- this is a mechanical refactoring with no external dependency concerns diff --git a/.planning/phases/04-deprecated-ccc-api-replacement/04-VERIFICATION.md b/.planning/phases/04-deprecated-ccc-api-replacement/04-VERIFICATION.md deleted file mode 100644 index 47f2061..0000000 --- a/.planning/phases/04-deprecated-ccc-api-replacement/04-VERIFICATION.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -phase: 04-deprecated-ccc-api-replacement -verified: 2026-02-26T12:00:00Z -status: passed -score: 5/5 must-haves verified -re_verification: false ---- - -# Phase 4: Deprecated CCC API Replacement — Verification Report - -**Phase Goal:** UdtHandler dependency in @ickb/order is replaced with plain ccc.Script (udtScript); UDT cellDeps management removed from OrderManager (caller/CCC Udt handles externally during balance completion); @ickb/dao verified clean (no UdtHandler, no deprecated APIs); Phase 3 decision doc corrected to match actual codebase state -**Verified:** 2026-02-26T12:00:00Z -**Status:** passed -**Re-verification:** No — initial verification - ---- - -## Goal Achievement - -### Observable Truths - -| # | Truth | Status | Evidence | -|---|-------|--------|----------| -| 1 | OrderManager constructor accepts `udtScript: ccc.Script` as its third parameter | VERIFIED | `packages/order/src/order.ts` line 26: `public readonly udtScript: ccc.Script,` | -| 2 | OrderManager methods do not add UDT cellDeps to transactions | VERIFIED | No `tx.addCellDeps(this.udtHandler.cellDeps)` in order.ts; grep returns exit 1 (no matches) | -| 3 | @ickb/order does not import UdtHandler from @ickb/utils | VERIFIED | Import block at top of order.ts has no `UdtHandler`; `grep -r "UdtHandler" packages/order/src/` returns exit 1 | -| 4 | SDK constructs OrderManager with ickbUdt.script (a ccc.Script), not full IckbUdtManager instance | VERIFIED | `packages/sdk/src/constants.ts` line 78: `new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script)` | -| 5 | pnpm check:full passes with zero errors | VERIFIED | `pnpm check` exit code 0; lint, build, test all pass; only warnings are chunk size and missing codec exports (pre-existing, unrelated to Phase 4) | - -**Score:** 5/5 truths verified - ---- - -### Required Artifacts - -| Artifact | Expected | Status | Details | -|----------|----------|--------|---------| -| `packages/order/src/order.ts` | OrderManager with udtScript: ccc.Script parameter, no UDT cellDeps | VERIFIED | Contains `public readonly udtScript: ccc.Script` at line 26; no `udtHandler` references; @remarks JSDoc on mint (line 162), addMatch (line 218), melt (line 499) | -| `packages/sdk/src/constants.ts` | SDK caller passing ickbUdt.script to OrderManager | VERIFIED | Line 78: `new OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script)` | - ---- - -### Key Link Verification - -| From | To | Via | Status | Details | -|------|----|-----|--------|---------| -| `packages/sdk/src/constants.ts` | `packages/order/src/order.ts` | OrderManager constructor call | VERIFIED | Line 78 matches pattern `new OrderManager(.*ickbUdt\.script)` | -| `packages/order/src/order.ts` | `@ckb-ccc/core` | ccc.Script type for udtScript | VERIFIED | Line 26: `udtScript: ccc.Script`; imports `ccc` from `@ckb-ccc/core` at line 1 | - ---- - -### Requirements Coverage - -| Requirement | Source Plan | Description | Status | Evidence | -|-------------|-------------|-------------|--------|----------| -| SMTX-05 | 04-01-PLAN.md | UDT handler registration replaced by direct Udt instance usage or standalone utility functions | PARTIAL (Phase 4 contribution verified) | Phase 4 scope: OrderManager.udtHandler replaced with udtScript: ccc.Script, UDT cellDeps removed (caller responsibility). Per REQUIREMENTS.md traceability, SMTX-05 spans Phases 1, 4, and 5. Phase 4's portion is fully delivered. Final completion awaits Phase 5 (UdtHandler/UdtManager deletion from @ickb/utils). | - -**Note on SMTX-05 scope:** The requirement spans three phases. Phase 4 owns the OrderManager portion only. `UdtHandler` interface and `UdtManager` class intentionally remain in `@ickb/utils` and `@ickb/core` — their deletion is Phase 5 work. The REQUIREMENTS.md traceability table and the Phase 3 decision doc both confirm this split. No orphaned requirements found. - ---- - -### Supplementary Verifications - -**@ickb/dao clean check:** -- `grep -r "UdtHandler|udtHandler" packages/dao/src/` — exit 1 (no matches). Clean. -- `grep -r "udtBalanceFrom|getInputsUdtBalance|getOutputsUdtBalance|completeInputsByUdt" packages/dao/src/` — exit 1 (no matches). Clean. - -**Phase 3 decision doc correction:** -- `03-DECISION.md` line 373 contains: `*Updated 2026-02-26 based on Phase 4 discuss-phase. See 04-CONTEXT.md for full decisions.*` -- Line 266 references `udtScript: ccc.Script (Phase 4)` in the change table. -- Line 378 states `udtHandler: UdtHandler replaced with udtScript: ccc.Script`. -- Correction is present and accurate. - -**Commit verification:** -- Commit `9e6e3d8` exists: `feat(04-01): replace UdtHandler with udtScript in OrderManager` -- Modified files: `packages/order/src/order.ts` and `packages/sdk/src/constants.ts` — exactly the planned files. - ---- - -### Anti-Patterns Found - -| File | Line | Pattern | Severity | Impact | -|------|------|---------|----------|--------| -| `packages/order/src/order.ts` | 33 | JSDoc still says "UDT handler's script" in `isOrder()` description | Info | Cosmetic only — code uses `this.udtScript` correctly; JSDoc description is stale prose, not a stub | -| `packages/order/src/order.ts` | 534 | JSDoc says "lock-script cells matching order & UDT handler" in `findOrders()` | Info | Cosmetic only — implementation uses `this.udtScript` correctly at line 637 | - -Neither anti-pattern affects correctness or the phase goal. Both are stale JSDoc prose from before the refactor. - ---- - -### Human Verification Required - -None. All phase goals are verifiable programmatically: -- Parameter type changes are statically verified by TypeScript (pnpm check passes). -- cellDeps calls are verifiable by grep. -- SDK wiring is verifiable by grep. -- Phase 3 decision doc correction is verifiable by grep. - ---- - -### Summary - -Phase 4 goal is fully achieved. Every must-have truth is verified against the actual codebase: - -1. `OrderManager` constructor parameter is `udtScript: ccc.Script` — confirmed in source. -2. All three `tx.addCellDeps(this.udtHandler.cellDeps)` calls are removed from `mint()`, `addMatch()`, `melt()` — grep returns no matches. -3. `UdtHandler` import is absent from `@ickb/order` — grep returns no matches across the entire `packages/order/src/` directory. -4. SDK passes `ickbUdt.script` (not `ickbUdt`) to the OrderManager constructor — confirmed at constants.ts line 78. -5. `pnpm check` passes with exit code 0, confirming TypeScript type safety across all 5 library packages. - -The presence of `UdtHandler` in `@ickb/utils` and `@ickb/core` is expected and intentional — those are deferred to Phase 5 per the roadmap and REQUIREMENTS.md traceability. - -Two stale JSDoc strings (lines 33 and 534 of order.ts) describe the old "UDT handler" concept — these are cosmetic and do not affect goal achievement. - -SMTX-05 is "In Progress" spanning Phases 1, 4, and 5. Phase 4's contribution (OrderManager refactor) is complete. Phase 5 will complete it by deleting `UdtHandler`/`UdtManager` from `@ickb/utils`. - ---- - -_Verified: 2026-02-26T12:00:00Z_ -_Verifier: AI Coworker (gsd-verifier)_ diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-01-PLAN.md b/.planning/phases/05-ickb-core-udt-refactor/05-01-PLAN.md deleted file mode 100644 index 6176e68..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-01-PLAN.md +++ /dev/null @@ -1,497 +0,0 @@ ---- -phase: 05-ickb-core-udt-refactor -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - pnpm-workspace.yaml - - packages/core/package.json - - packages/core/src/udt.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts -autonomous: true -requirements: - - SMTX-05 - - SMTX-07 - - SMTX-10 - - UDT-04 - -must_haves: - truths: - - "IckbUdt extends udt.Udt exists in @ickb/core with infoFrom override" - - "infoFrom correctly values xUDT cells (positive), receipt cells (positive, input only), deposit cells (negative, input only)" - - "IckbUdt.addCellDeps adds individual code deps (xUDT + Logic OutPoints), not dep group" - - "IckbUdt.typeScriptFrom static method computes iCKB UDT type script" - - "LogicManager no longer takes udtHandler parameter" - - "OwnedOwnerManager no longer takes udtHandler parameter" - - "No tx.addCellDeps(this.udtHandler.cellDeps) calls remain in LogicManager or OwnedOwnerManager" - artifacts: - - path: "packages/core/src/udt.ts" - provides: "IckbUdt class extending udt.Udt with infoFrom, addCellDeps, typeScriptFrom" - contains: "class IckbUdt extends udt.Udt" - - path: "packages/core/src/logic.ts" - provides: "LogicManager without udtHandler parameter" - - path: "packages/core/src/owned_owner.ts" - provides: "OwnedOwnerManager without udtHandler parameter" - - path: "packages/core/package.json" - provides: "@ckb-ccc/udt dependency" - contains: "@ckb-ccc/udt" - - path: "pnpm-workspace.yaml" - provides: "Catalog entry for @ckb-ccc/udt" - contains: "@ckb-ccc/udt" - key_links: - - from: "packages/core/src/udt.ts" - to: "@ckb-ccc/udt" - via: "import { udt } from '@ckb-ccc/udt'" - pattern: "import.*udt.*from.*@ckb-ccc/udt" - - from: "packages/core/src/udt.ts" - to: "packages/core/src/entities.ts" - via: "ReceiptData.decode for receipt cell valuation" - pattern: "ReceiptData\\.decode" - - from: "packages/core/src/udt.ts" - to: "@ickb/dao" - via: "DaoManager for deposit cell identification" - pattern: "daoManager\\.isDeposit" ---- - - -Implement IckbUdt class extending CCC's udt.Udt in @ickb/core, replacing IckbUdtManager. Remove udtHandler parameter from LogicManager and OwnedOwnerManager. Add @ckb-ccc/udt dependency. - -Purpose: This is the core CCC UDT integration -- IckbUdt.infoFrom provides accurate multi-representation balance (xUDT + receipts + deposits) consumed by CCC's completeInputsByBalance pipeline. Removing udtHandler from managers follows the Phase 4 OrderManager pattern, making UDT cellDeps a caller responsibility. - -Output: Modified core/src/udt.ts (IckbUdt class), modified logic.ts and owned_owner.ts (no udtHandler), updated package.json and catalog. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/05-ickb-core-udt-refactor/05-CONTEXT.md -@.planning/phases/05-ickb-core-udt-refactor/05-RESEARCH.md - - - - -From @ckb-ccc/udt (CCC Udt class -- the base class to extend): -```typescript -import { udt } from "@ckb-ccc/udt"; - -// Constructor: (code: OutPointLike, script: ScriptLike, config?: UdtConfigLike | null) -// - code: xUDT code cell OutPoint (passed to ssri.Trait) -// - script: iCKB UDT type script (token identity) -// No executor needed (legacy xUDT, not SSRI) - -class Udt extends ssri.Trait { - public readonly script: ccc.Script; - public readonly filter: ccc.ClientIndexerSearchKeyFilter; - - constructor(code: ccc.OutPointLike, script: ccc.ScriptLike, config?: UdtConfigLike | null); - - // Override this for multi-representation balance - async infoFrom( - _client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: UdtInfoLike, - ): Promise; - - // Override this for custom cellDeps - addCellDeps(txLike: ccc.TransactionLike): ccc.Transaction; - - // Checks cell.type matches this.script AND outputData >= 16 bytes - isUdt(cell: ccc.CellAnyLike): boolean; - - // Extracts balance from outputData (LE uint128) - static balanceFromUnsafe(outputData: ccc.HexLike): ccc.Num; -} - -class UdtInfo { - balance: ccc.Num; - capacity: ccc.Num; - count: number; - static from(infoLike?: UdtInfoLike): UdtInfo; - clone(): UdtInfo; - addAssign(infoLike: UdtInfoLike): this; -} -``` - -From packages/core/src/udt.ts (BEFORE -- current IckbUdtManager to replace): -```typescript -export class IckbUdtManager extends UdtManager implements UdtHandler { - constructor( - script: ccc.Script, - cellDeps: ccc.CellDep[], - public readonly logicScript: ccc.Script, - public readonly daoManager: DaoManager, - ) { super(script, cellDeps, "iCKB", "iCKB", 8); } - - static calculateScript(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script; - override async getInputsUdtBalance(client, txLike): Promise<[FixedPoint, FixedPoint]>; -} - -// These functions/constants MUST be preserved unchanged: -export function ickbValue(ckbUnoccupiedCapacity, header): FixedPoint; -export function convert(isCkb2Udt, amount, rate, accountDepositCapacity?): FixedPoint; -export function ickbExchangeRatio(header, accountDepositCapacity?): ExchangeRatio; -export const ICKB_DEPOSIT_CAP; -// Internal constants (AR_0, depositUsedCapacity, depositCapacityDelta) also preserved -``` - -From packages/core/src/entities.ts: -```typescript -export const ReceiptData = { - decode(data: ccc.HexLike): { depositQuantity: bigint; depositAmount: bigint }; - encode(data: { depositQuantity: number; depositAmount: bigint }): ccc.Hex; -}; -``` - -From @ickb/dao: -```typescript -export class DaoManager { - isDeposit(cell: ccc.Cell): boolean; // Checks outputData for 8 zero bytes -} -``` - -From packages/core/src/logic.ts (BEFORE -- udtHandler to remove): -```typescript -export class LogicManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - public readonly udtHandler: UdtHandler, // REMOVE - ) {} - // Line 88: tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE (in deposit) - // Line 125: tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE (in completeDeposit) -} -``` - -From packages/core/src/owned_owner.ts (BEFORE -- udtHandler to remove): -```typescript -export class OwnedOwnerManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - public readonly udtHandler: UdtHandler, // REMOVE - ) {} - // Line 95: tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE (in requestWithdrawal) - // Line 140: tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE (in withdraw) -} -``` - - - - - - - Task 1: Add @ckb-ccc/udt dependency and implement IckbUdt class - pnpm-workspace.yaml, packages/core/package.json, packages/core/src/udt.ts - -**Step 1: Add catalog entry in `pnpm-workspace.yaml`** - -Add `"@ckb-ccc/udt": ^1.12.2` to the catalog section, after the existing `"@ckb-ccc/core": ^1.12.2` entry. This ensures consistency with how `@ckb-ccc/core` is referenced. The `.pnpmfile.cjs` hook will rewrite to `workspace:*` when the local CCC fork is present. - -**Step 2: Add dependency in `packages/core/package.json`** - -Add `"@ckb-ccc/udt": "catalog:"` to the dependencies object, after `"@ckb-ccc/core": "catalog:"`. The dependencies section should become: -```json -"dependencies": { - "@ckb-ccc/core": "catalog:", - "@ckb-ccc/udt": "catalog:", - "@ickb/dao": "workspace:*", - "@ickb/utils": "workspace:*" -} -``` - -**Step 3: Run `pnpm install` to update lockfile** - -**Step 4: Rewrite `packages/core/src/udt.ts`** - -Replace the entire `IckbUdtManager` class with `IckbUdt extends udt.Udt`. Keep all standalone functions (`ickbValue`, `convert`, `ickbExchangeRatio`) and constants (`ICKB_DEPOSIT_CAP`, `AR_0`, `depositUsedCapacity`, `depositCapacityDelta`) UNCHANGED. - -New imports (replacing current imports): -```typescript -import { ccc } from "@ckb-ccc/core"; -import { udt } from "@ckb-ccc/udt"; -import { ReceiptData } from "./entities.js"; -import type { DaoManager } from "@ickb/dao"; -import type { ExchangeRatio } from "@ickb/utils"; -``` - -Note: `UdtManager` and `UdtHandler` imports are removed. `ExchangeRatio` is kept (used by `convert` function). `udt` namespace import is added from `@ckb-ccc/udt`. - -New class definition: -```typescript -/** - * IckbUdt extends CCC's Udt class to provide accurate multi-representation - * balance for iCKB tokens. The iCKB conservation law is: - * Input UDT + Input Receipts = Output UDT + Input Deposits - * - * `infoFrom` values three cell types: - * - xUDT cells: positive balance (standard UDT) - * - Receipt cells: positive balance (input only, valued via ickbValue) - * - Deposit cells: negative balance (input only, withdrawal reduces UDT supply) - * - * Output cells without outPoint are naturally excluded from receipt/deposit - * processing, since only input cells (resolved by CellInput.getCell()) have outPoint. - */ -export class IckbUdt extends udt.Udt { - public readonly logicCode: ccc.OutPoint; - public readonly logicScript: ccc.Script; - public readonly daoManager: DaoManager; - - /** - * Creates an instance of IckbUdt. - * - * @param code - The xUDT code cell OutPoint (passed to base Udt/Trait). - * @param script - The iCKB UDT type script (token identity via args). - * @param logicCode - The iCKB Logic code cell OutPoint. - * @param logicScript - The iCKB Logic script. - * @param daoManager - The DAO manager instance for deposit cell identification. - */ - constructor( - code: ccc.OutPointLike, - script: ccc.ScriptLike, - logicCode: ccc.OutPointLike, - logicScript: ccc.ScriptLike, - daoManager: DaoManager, - ) { - super(code, script); - this.logicCode = ccc.OutPoint.from(logicCode); - this.logicScript = ccc.Script.from(logicScript); - this.daoManager = daoManager; - } - - /** - * Computes the iCKB UDT type script from raw UDT and Logic scripts. - * - * Concatenates the iCKB logic script hash with a fixed 4-byte LE length - * postfix ("00000080") to form the UDT type script args. - * - * @param udt - The raw xUDT script (codeHash and hashType reused). - * @param ickbLogic - The iCKB logic script (hash used for args). - * @returns A new Script with the computed args. - */ - static typeScriptFrom(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script { - const { codeHash, hashType } = udt; - return new ccc.Script( - codeHash, - hashType, - [ickbLogic.hash(), "00000080"].join("") as ccc.Hex, - ); - } - - /** - * Computes UDT balance info for iCKB's three cell representations. - * - * For each cell: - * - xUDT cell (type === this.script, data >= 16 bytes): adds positive balance - * - Receipt cell (type === logicScript, has outPoint): adds positive balance - * via ickbValue of deposit amount * quantity - * - Deposit cell (lock === logicScript, isDeposit, has outPoint): adds negative - * balance via ickbValue of free capacity (withdrawal reduces UDT supply) - * - * Cells without outPoint (output cells from getOutputsInfo) skip receipt/deposit - * processing -- correct by design since these only appear as inputs. - * - * @param client - CKB client for header fetches (receipt/deposit valuation). - * @param cells - Cell or array of cells to evaluate. - * @param acc - Optional accumulator for running totals. - * @returns UdtInfo with balance, capacity, and count. - */ - override async infoFrom( - client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: udt.UdtInfoLike, - ): Promise { - const info = udt.UdtInfo.from(acc).clone(); - - for (const cellLike of [cells].flat()) { - const cell = ccc.CellAny.from(cellLike); - - // Standard xUDT cell -- delegate to base class pattern - if (this.isUdt(cell)) { - info.addAssign({ - balance: udt.Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Receipt and deposit cells need outPoint for header fetch. - // Output cells (no outPoint) are skipped -- correct by design. - if (!cell.outPoint) { - continue; - } - - const { type, lock } = cell.cellOutput; - - // Receipt cell: type === logicScript - if (type && this.logicScript.eq(type)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); - } - - const { depositQuantity, depositAmount } = - ReceiptData.decode(cell.outputData); - info.addAssign({ - balance: ickbValue(depositAmount, txWithHeader.header) * - depositQuantity, - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Deposit cell: lock === logicScript AND isDeposit - if (this.logicScript.eq(lock) && this.daoManager.isDeposit(cell)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); - } - - info.addAssign({ - balance: -ickbValue(cell.capacityFree, txWithHeader.header), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - } - - return info; - } - - /** - * Adds iCKB-specific cell dependencies to a transaction. - * - * Adds individual code deps (not dep group) for: - * - xUDT code cell (this.code from ssri.Trait) - * - iCKB Logic code cell (this.logicCode) - * - * @param txLike - The transaction to add cell deps to. - * @returns The transaction with cell deps added. - */ - override addCellDeps(txLike: ccc.TransactionLike): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - // xUDT code dep - tx.addCellDeps({ outPoint: this.code, depType: "code" }); - // iCKB Logic code dep - tx.addCellDeps({ outPoint: this.logicCode, depType: "code" }); - return tx; - } -} -``` - -**Key implementation notes:** -- `daoManager.isDeposit(cell)` receives a `CellAny` from `CellAny.from(cellLike)`. In `infoFrom` called from `getInputsInfo`, input cells are resolved via `CellInput.getCell()` which returns `Cell` (extends `CellAny`). `DaoManager.isDeposit` takes `ccc.Cell`, and `Cell extends CellAny`, so this works for input cells. For output cells, the `!cell.outPoint` check gates them before `isDeposit` is reached. -- `balance` in `UdtInfo` uses `ccc.Num` (bigint), which can go negative for deposit cells. This is intentional -- CCC's `completeInputsByBalance` checks `info.balance >= 0` to stop. -- The `ickbValue` call for receipt cells multiplies by `depositQuantity` (a receipt can represent multiple deposits). -- The `ickbValue` call for deposit cells uses `cell.capacityFree` (available via `CellAny.capacityFree` getter). - -**PRESERVE all code below the class definition unchanged:** -- `ickbValue` function -- `ICKB_DEPOSIT_CAP` constant -- `convert` function -- `ickbExchangeRatio` function -- `AR_0`, `depositUsedCapacity`, `depositCapacityDelta` constants - - - cd /workspaces/stack && pnpm install && grep -q "@ckb-ccc/udt" pnpm-workspace.yaml && grep -q "@ckb-ccc/udt" packages/core/package.json && grep -q "class IckbUdt extends udt.Udt" packages/core/src/udt.ts && grep -q "typeScriptFrom" packages/core/src/udt.ts && echo "PASS" - - - - @ckb-ccc/udt added to pnpm-workspace.yaml catalog - - @ckb-ccc/udt added to @ickb/core package.json dependencies - - IckbUdt extends udt.Udt class exists with infoFrom, addCellDeps, typeScriptFrom - - IckbUdtManager class no longer exists - - calculateScript renamed to typeScriptFrom (static) - - No imports of UdtManager or UdtHandler from @ickb/utils in core/src/udt.ts - - All standalone functions and constants preserved unchanged - - - - - Task 2: Remove udtHandler from LogicManager and OwnedOwnerManager - packages/core/src/logic.ts, packages/core/src/owned_owner.ts - -**In `packages/core/src/logic.ts`:** - -1. Remove `type UdtHandler,` from the `@ickb/utils` import on line 6. Keep `defaultFindCellsLimit`, `type ScriptDeps`, `unique`. - -2. Update JSDoc on line 29: remove `@param udtHandler - The handler for User Defined Tokens (UDTs).` - -3. Remove constructor parameter on line 34: delete `public readonly udtHandler: UdtHandler,` - -4. In `deposit()` method (line 88): delete `tx.addCellDeps(this.udtHandler.cellDeps);` - Add JSDoc `@remarks` to deposit()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via ickbUdt.addCellDeps(tx)).` - -5. In `completeDeposit()` method (line 125): delete `tx.addCellDeps(this.udtHandler.cellDeps);` - Add JSDoc `@remarks` to completeDeposit()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via ickbUdt.addCellDeps(tx)).` - -**In `packages/core/src/owned_owner.ts`:** - -1. Remove `type UdtHandler,` from the `@ickb/utils` import on line 6. Keep `defaultFindCellsLimit`, `unique`, `type ScriptDeps`. - -2. Update JSDoc on line 24: remove `@param udtHandler - The handler for User Defined Tokens (UDTs).` - -3. Remove constructor parameter on line 29: delete `public readonly udtHandler: UdtHandler,` - -4. In `requestWithdrawal()` method (line 95): delete `tx.addCellDeps(this.udtHandler.cellDeps);` - Add JSDoc `@remarks` to requestWithdrawal()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via ickbUdt.addCellDeps(tx)).` - -5. In `withdraw()` method (line 140): delete `tx.addCellDeps(this.udtHandler.cellDeps);` - Add JSDoc `@remarks` to withdraw()'s existing JSDoc block: `@remarks Caller must ensure UDT cellDeps are added to the transaction (e.g., via ickbUdt.addCellDeps(tx)).` - -This matches Phase 4's OrderManager pattern exactly. UDT cellDeps are now caller responsibility -- documented via JSDoc @remarks. - - - cd /workspaces/stack && ! grep -rq "UdtHandler\|udtHandler" packages/core/src/logic.ts packages/core/src/owned_owner.ts && echo "PASS" - - - - LogicManager constructor has 3 parameters (script, cellDeps, daoManager) -- no udtHandler - - OwnedOwnerManager constructor has 3 parameters (script, cellDeps, daoManager) -- no udtHandler - - All 4 tx.addCellDeps(this.udtHandler.cellDeps) calls deleted (2 in logic.ts, 2 in owned_owner.ts) - - UdtHandler no longer imported in either file - - JSDoc @remarks added to deposit(), completeDeposit(), requestWithdrawal(), withdraw() about caller cellDeps responsibility - - - - - - -1. `grep -q "class IckbUdt extends udt.Udt" packages/core/src/udt.ts` confirms IckbUdt class exists -2. `grep -q "typeScriptFrom" packages/core/src/udt.ts` confirms renamed static method -3. `grep -q "override async infoFrom" packages/core/src/udt.ts` confirms infoFrom override -4. `grep -q "override addCellDeps" packages/core/src/udt.ts` confirms addCellDeps override -5. `grep -r "UdtHandler\|udtHandler" packages/core/src/logic.ts packages/core/src/owned_owner.ts` returns no matches -6. `grep -r "UdtManager\|IckbUdtManager" packages/core/src/udt.ts` returns no matches (old class removed) -7. `grep -q "@ckb-ccc/udt" packages/core/package.json` confirms dependency added -8. `grep -q "@ckb-ccc/udt" pnpm-workspace.yaml` confirms catalog entry added - - - -- IckbUdt extends udt.Udt with infoFrom override for multi-representation balance -- addCellDeps override adds individual code deps (xUDT + Logic) -- typeScriptFrom static method replaces calculateScript -- LogicManager and OwnedOwnerManager no longer take udtHandler parameter -- All 4 udtHandler.cellDeps calls removed from managers -- @ckb-ccc/udt dependency added to core package.json and workspace catalog -- No imports of UdtManager, UdtHandler, or IckbUdtManager remain in @ickb/core -- All standalone functions (ickbValue, convert, ickbExchangeRatio) and constants preserved unchanged - - - -After completion, create `.planning/phases/05-ickb-core-udt-refactor/05-01-SUMMARY.md` - diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-01-SUMMARY.md b/.planning/phases/05-ickb-core-udt-refactor/05-01-SUMMARY.md deleted file mode 100644 index a2793ed..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-01-SUMMARY.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -phase: 05-ickb-core-udt-refactor -plan: 01 -subsystem: core -tags: [udt, ccc, xudt, ickb, balance, cellDeps] - -# Dependency graph -requires: - - phase: 04-deprecated-api-udt-pattern - provides: UDT pattern (managers receive ccc.Script, cellDeps are caller responsibility) - - phase: 03-udt-investigation - provides: IckbUdt subclass design (infoFrom override for multi-representation balance) -provides: - - IckbUdt class extending udt.Udt with infoFrom, addCellDeps, typeScriptFrom - - LogicManager without udtHandler parameter - - OwnedOwnerManager without udtHandler parameter - - "@ckb-ccc/udt" dependency in @ickb/core -affects: [05-02, sdk, bot] - -# Tech tracking -tech-stack: - added: ["@ckb-ccc/udt"] - patterns: [IckbUdt subclass with multi-representation infoFrom, individual code deps] - -key-files: - created: [] - modified: - - packages/core/src/udt.ts - - packages/core/src/logic.ts - - packages/core/src/owned_owner.ts - - packages/core/package.json - - pnpm-workspace.yaml - -key-decisions: - - "IckbUdt.infoFrom handles three cell types: xUDT (positive), receipt (positive via ickbValue), deposit (negative via ickbValue)" - - "addCellDeps adds individual code deps (xUDT + Logic OutPoints), not dep group" - - "Widened DaoManager.isDeposit to accept CellAny — cleaner than type assertion, only inspects fields CellAny provides" - -patterns-established: - - "IckbUdt subclass pattern: extend udt.Udt, override infoFrom for custom balance, override addCellDeps for custom deps" - - "Manager cellDeps responsibility: managers document caller responsibility via JSDoc @remarks" - -requirements-completed: [SMTX-05, SMTX-07, SMTX-10, UDT-04] - -# Metrics -duration: 7min -completed: 2026-02-26 ---- - -# Phase 5 Plan 1: IckbUdt Implementation Summary - -**IckbUdt extends CCC udt.Udt with multi-representation balance (xUDT + receipts + deposits) and individual code deps; udtHandler removed from LogicManager and OwnedOwnerManager** - -## Performance - -- **Duration:** 7 min -- **Started:** 2026-02-26T16:05:59Z -- **Completed:** 2026-02-26T16:12:50Z -- **Tasks:** 2 -- **Files modified:** 5 - -## Accomplishments -- Replaced IckbUdtManager with IckbUdt extending CCC's udt.Udt class, providing accurate multi-representation balance via infoFrom override -- Added addCellDeps override with individual code deps (xUDT + Logic OutPoints) instead of dep group -- Renamed calculateScript to typeScriptFrom static method -- Removed udtHandler parameter and cellDeps calls from LogicManager (deposit, completeDeposit) and OwnedOwnerManager (requestWithdrawal, withdraw) -- Added @ckb-ccc/udt dependency to workspace catalog and @ickb/core - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Add @ckb-ccc/udt dependency and implement IckbUdt class** - `4cd87ea` (feat) -2. **Task 2: Remove udtHandler from LogicManager and OwnedOwnerManager** - `e5dd4c3` (refactor) - -## Files Created/Modified -- `packages/core/src/udt.ts` - IckbUdt class extending udt.Udt with infoFrom, addCellDeps, typeScriptFrom; standalone functions preserved -- `packages/core/src/logic.ts` - LogicManager without udtHandler; JSDoc @remarks on deposit/completeDeposit -- `packages/core/src/owned_owner.ts` - OwnedOwnerManager without udtHandler; JSDoc @remarks on requestWithdrawal/withdraw -- `packages/core/package.json` - Added @ckb-ccc/udt dependency -- `pnpm-workspace.yaml` - Added @ckb-ccc/udt catalog entry - -## Decisions Made -- Widened DaoManager.isDeposit() to accept CellAny instead of adding a type assertion — cleaner than casting, and isDeposit only inspects cellOutput.type and outputData which CellAny provides -- addCellDeps adds individual code deps (not dep group) per CCC author preference, matching 05-CONTEXT decision - -## Deviations from Plan - -### Auto-fixed Issues - -**1. [Rule 1 - Bug] Widened DaoManager.isDeposit to accept CellAny** -- **Found during:** Task 1 (IckbUdt class implementation) -- **Issue:** daoManager.isDeposit() takes ccc.Cell but infoFrom processes CellAny; TypeScript type mismatch -- **Fix:** Widened DaoManager.isDeposit() parameter from ccc.Cell to ccc.CellAny in packages/dao/src/dao.ts (cleaner than a type assertion) -- **Files modified:** packages/dao/src/dao.ts -- **Verification:** TypeScript compilation passes with no errors across all packages - ---- - -**Total deviations:** 1 auto-fixed (1 bug fix) -**Impact on plan:** Upstream signature widened for type correctness. Runtime behavior unchanged. No scope creep. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- IckbUdt class ready for SDK integration (05-02) -- UdtHandler interface has zero consumers in core after this plan -- ready for deletion in 05-02 -- All standalone functions (ickbValue, convert, ickbExchangeRatio) preserved unchanged for downstream consumers - -## Self-Check: PASSED - -All files exist, all commits verified. - ---- -*Phase: 05-ickb-core-udt-refactor* -*Completed: 2026-02-26* diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-02-PLAN.md b/.planning/phases/05-ickb-core-udt-refactor/05-02-PLAN.md deleted file mode 100644 index f844bb1..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-02-PLAN.md +++ /dev/null @@ -1,418 +0,0 @@ ---- -phase: 05-ickb-core-udt-refactor -plan: 02 -type: execute -wave: 2 -depends_on: ["05-01"] -files_modified: - - packages/utils/src/udt.ts - - packages/utils/src/index.ts - - packages/sdk/src/constants.ts -autonomous: true -requirements: - - SMTX-05 - - SMTX-07 - - SMTX-10 - - UDT-04 - -must_haves: - truths: - - "UdtHandler interface, UdtManager class, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol are deleted from @ickb/utils" - - "packages/utils/src/udt.ts file no longer exists" - - "@ickb/utils no longer exports any UDT-related types" - - "SDK constructs IckbUdt instead of IckbUdtManager" - - "SDK passes ickbUdt.script to OrderManager" - - "LogicManager and OwnedOwnerManager constructed without ickbUdt argument" - - "pnpm check:full passes with zero errors" - - "SDK audited for ErrorTransactionInsufficientCoin catch blocks -- zero found, no migration required; ErrorUdtInsufficientCoin is CCC's responsibility and surfaces to callers unchanged" - artifacts: - - path: "packages/utils/src/index.ts" - provides: "Barrel export without udt.ts" - - path: "packages/sdk/src/constants.ts" - provides: "getConfig() constructing IckbUdt with code OutPoints" - contains: "new IckbUdt" - key_links: - - from: "packages/sdk/src/constants.ts" - to: "packages/core/src/udt.ts" - via: "import { IckbUdt } and constructor call" - pattern: "new IckbUdt\\(" - - from: "packages/sdk/src/constants.ts" - to: "packages/core/src/udt.ts" - via: "IckbUdt.typeScriptFrom for script computation" - pattern: "IckbUdt\\.typeScriptFrom" ---- - - -Delete UDT infrastructure from @ickb/utils (UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol). Update SDK to construct IckbUdt with individual code OutPoints instead of IckbUdtManager with dep group. Verify the full stack compiles. - -Purpose: With IckbUdt replacing IckbUdtManager (Plan 05-01) and all managers cleaned of udtHandler references, the entire UDT infrastructure in @ickb/utils has zero consumers. Deleting it eliminates ~400 lines of duplicated code. The SDK wiring completes the refactor by constructing IckbUdt with the CCC-aligned code OutPoint pattern. - -Output: Deleted utils/src/udt.ts, updated utils/src/index.ts, rewritten SDK constants.ts. Full stack compiles via pnpm check:full. - - - -@/home/node/.claude/get-shit-done/workflows/execute-plan.md -@/home/node/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/phases/05-ickb-core-udt-refactor/05-CONTEXT.md -@.planning/phases/05-ickb-core-udt-refactor/05-RESEARCH.md -@.planning/phases/05-ickb-core-udt-refactor/05-01-SUMMARY.md - - - - -From packages/core/src/udt.ts (AFTER Plan 05-01 -- new IckbUdt class): -```typescript -import { udt } from "@ckb-ccc/udt"; - -export class IckbUdt extends udt.Udt { - constructor( - code: ccc.OutPointLike, // xUDT code cell OutPoint - script: ccc.ScriptLike, // iCKB UDT type script - logicCode: ccc.OutPointLike, // iCKB Logic code cell OutPoint - logicScript: ccc.ScriptLike, // iCKB Logic script - daoManager: DaoManager, // DAO manager for deposit detection - ); - static typeScriptFrom(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script; - override async infoFrom(client, cells, acc?): Promise; - override addCellDeps(txLike): ccc.Transaction; -} -``` - -From packages/core/src/logic.ts (AFTER Plan 05-01 -- no udtHandler): -```typescript -export class LogicManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - // udtHandler REMOVED - ) {} -} -``` - -From packages/core/src/owned_owner.ts (AFTER Plan 05-01 -- no udtHandler): -```typescript -export class OwnedOwnerManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - // udtHandler REMOVED - ) {} -} -``` - -From packages/sdk/src/constants.ts (BEFORE -- current state to modify): -```typescript -import { IckbUdtManager, LogicManager, OwnedOwnerManager } from "@ickb/core"; - -export function getConfig(d, bots): { - managers: { - dao: DaoManager; - ickbUdt: IckbUdtManager; // CHANGE to IckbUdt - logic: LogicManager; - ownedOwner: OwnedOwnerManager; - order: OrderManager; - }; - bots: ccc.Script[]; -} - -// Current construction: -const ickbUdt = new IckbUdtManager( - d.udt.script, // script - d.udt.cellDeps, // cellDeps (dep group) - d.logic.script, // logicScript - dao, // daoManager -); -const logic = new LogicManager(d.logic.script, d.logic.cellDeps, dao, ickbUdt); -const ownedOwner = new OwnedOwnerManager(d.ownedOwner.script, d.ownedOwner.cellDeps, dao, ickbUdt); -``` - -Code cell OutPoints for IckbUdt construction (from forks/contracts/scripts/deployment/): -``` -Mainnet xUDT code: txHash 0xc07844ce21b38e4b071dd0e1ee3b0e27afd8d7532491327f39b786343f558ab7, index 0x0 -Mainnet Logic code: txHash 0xd7309191381f5a8a2904b8a79958a9be2752dbba6871fa193dab6aeb29dc8f44, index 0x0 -Testnet xUDT code: txHash 0xbf6fb538763efec2a70a6a3dcb7242787087e1030c4e7d86585bc63a9d337f5f, index 0x0 -Testnet Logic code: txHash 0x9ac989b3355764f76cdce02c69dedb819fdfbcbda49a7db1a2c9facdfdb9a7fe, index 0x0 -``` - -ScriptDeps interface (PRESERVED in @ickb/utils -- NOT deleted): -```typescript -// From packages/utils/src/utils.ts -export interface ScriptDeps { - script: ccc.Script; - cellDeps: ccc.CellDep[]; -} -``` - - - - - - - Task 1: Delete utils/src/udt.ts and update barrel export - packages/utils/src/udt.ts, packages/utils/src/index.ts - -**Step 1: Delete `packages/utils/src/udt.ts`** - -Delete the entire file. This removes: -- `UdtHandler` interface (zero consumers after Plan 05-01) -- `ErrorTransactionInsufficientCoin` class (zero catch blocks across entire codebase) -- `UdtManager` class (replaced by `IckbUdt extends udt.Udt`) -- `UdtCell` interface (internal to `UdtManager`) -- `findUdts` method (internal to `UdtManager`) -- `addUdts` method (internal to `UdtManager`) -- `isUdtSymbol` constant (internal to `UdtManager`) - -~406 lines deleted. - -**Step 2: Update `packages/utils/src/index.ts`** - -Remove the line `export * from "./udt.js";`. The file should become: -```typescript -export * from "./codec.js"; -export * from "./heap.js"; -export * from "./utils.js"; -``` - -**IMPORTANT: `ScriptDeps` interface is NOT in udt.ts.** It lives in `packages/utils/src/utils.ts` and has 6+ consumers remaining (DaoManager, LogicManager, OwnedOwnerManager, OrderManager, getConfig). It is preserved by this change. `ExchangeRatio` is also in `utils.ts`, not `udt.ts`. `ValueComponents` is also in `utils.ts`. All of these survive. - - - cd /workspaces/stack && ! test -f packages/utils/src/udt.ts && ! grep -q "udt.js" packages/utils/src/index.ts && grep -q "ScriptDeps" packages/utils/src/utils.ts && echo "PASS" - - - - packages/utils/src/udt.ts deleted (~406 lines removed) - - export * from "./udt.js" removed from index.ts - - UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol all gone - - ScriptDeps, ExchangeRatio, ValueComponents preserved in utils.ts (unaffected) - - - - - Task 2: Update SDK getConfig to construct IckbUdt with code OutPoints and verify full stack - packages/sdk/src/constants.ts - -**Step 1: Update imports in `packages/sdk/src/constants.ts`** - -Change the `@ickb/core` import from: -```typescript -import { IckbUdtManager, LogicManager, OwnedOwnerManager } from "@ickb/core"; -``` -to: -```typescript -import { IckbUdt, LogicManager, OwnedOwnerManager } from "@ickb/core"; -``` - -**Step 2: Add code cell OutPoint constants** - -Add these constants AFTER the existing script constants (after `ORDER` on line 154) and BEFORE the dep group constants (`MAINNET_DEP_GROUP` on line 159): - -```typescript -/** - * Mainnet xUDT code cell OutPoint. - * Source: forks/contracts/scripts/deployment/mainnet/deployment.toml - */ -const MAINNET_XUDT_CODE = { - txHash: - "0xc07844ce21b38e4b071dd0e1ee3b0e27afd8d7532491327f39b786343f558ab7", - index: "0x0", -}; - -/** - * Mainnet iCKB Logic code cell OutPoint. - * Source: forks/contracts/scripts/deployment/mainnet/deployment.toml - */ -const MAINNET_LOGIC_CODE = { - txHash: - "0xd7309191381f5a8a2904b8a79958a9be2752dbba6871fa193dab6aeb29dc8f44", - index: "0x0", -}; - -/** - * Testnet xUDT code cell OutPoint. - * Source: forks/contracts/scripts/deployment/testnet/deployment.toml - */ -const TESTNET_XUDT_CODE = { - txHash: - "0xbf6fb538763efec2a70a6a3dcb7242787087e1030c4e7d86585bc63a9d337f5f", - index: "0x0", -}; - -/** - * Testnet iCKB Logic code cell OutPoint. - * Source: forks/contracts/scripts/deployment/testnet/deployment.toml - */ -const TESTNET_LOGIC_CODE = { - txHash: - "0x9ac989b3355764f76cdce02c69dedb819fdfbcbda49a7db1a2c9facdfdb9a7fe", - index: "0x0", -}; -``` - -**Step 3: Update return type annotation** - -Change the return type from `ickbUdt: IckbUdtManager` to `ickbUdt: IckbUdt` (line 37). - -**Step 4: Rewrite IckbUdt construction in getConfig()** - -Replace the existing IckbUdtManager construction (lines 60-65): -```typescript -const ickbUdt = new IckbUdtManager( - d.udt.script, - d.udt.cellDeps, - d.logic.script, - dao, -); -``` - -For mainnet/testnet paths, the construction needs code OutPoints. The current flow creates `d` from `from(UDT, depGroup)` etc. which gives `ScriptDeps` with `script` and `cellDeps`. The `IckbUdt` constructor needs `code: OutPointLike` (xUDT code OutPoint) and `logicCode: OutPointLike` (Logic code OutPoint) which are NOT in `ScriptDeps`. - -For the mainnet/testnet case: extract code OutPoints based on the network string BEFORE it gets reassigned. The cleanest approach: - -Replace the entire IckbUdt construction block with: -```typescript -const isMainnet = typeof d !== "string" ? undefined : d === "mainnet"; -// ... after d is reassigned to ScriptDeps ... -const ickbUdt = new IckbUdt( - isMainnet !== undefined - ? (isMainnet ? MAINNET_XUDT_CODE : TESTNET_XUDT_CODE) - : d.udt.cellDeps[0]?.outPoint ?? { txHash: "0x", index: "0x0" }, - IckbUdt.typeScriptFrom( - ccc.Script.from(d.udt.script), - ccc.Script.from(d.logic.script), - ), - isMainnet !== undefined - ? (isMainnet ? MAINNET_LOGIC_CODE : TESTNET_LOGIC_CODE) - : d.logic.cellDeps[0]?.outPoint ?? { txHash: "0x", index: "0x0" }, - d.logic.script, - dao, -); -``` - -Wait -- the existing code reassigns `d` inside the `if` block. For devnet, `d` is already a config object. Let me trace the flow more carefully. - -Actually, the cleanest approach: capture the network string before `d` gets reassigned. - -Add `const isMainnet = ...` BEFORE the `if (d === "mainnet" || d === "testnet")` block: - -```typescript -const network = typeof d === "string" ? d : undefined; -``` - -Then the construction becomes: -```typescript -const ickbUdt = new IckbUdt( - network ? (network === "mainnet" ? MAINNET_XUDT_CODE : TESTNET_XUDT_CODE) - : d.udt.cellDeps[0]?.outPoint ?? { txHash: "0x", index: "0x0" }, - IckbUdt.typeScriptFrom( - ccc.Script.from(d.udt.script), - ccc.Script.from(d.logic.script), - ), - network ? (network === "mainnet" ? MAINNET_LOGIC_CODE : TESTNET_LOGIC_CODE) - : d.logic.cellDeps[0]?.outPoint ?? { txHash: "0x", index: "0x0" }, - d.logic.script, - dao, -); -``` - -Note: For devnet, the OutPoints are derived from the first cellDep's outPoint (best available from the ScriptDeps interface). The devnet config shape remains unchanged -- this is a pragmatic fallback. Document this with a comment. - -Alternative (simpler, per Claude's discretion): Since the devnet path is secondary and code OutPoints are only used by `addCellDeps`, devnet users can also use their dep group OutPoints as code OutPoints if their deps happen to be `depType: "code"` (which they are in local dev). Use `d.udt.cellDeps[0]?.outPoint` with a fallback. - -**Step 5: Update LogicManager and OwnedOwnerManager construction** - -Remove the `ickbUdt` argument from LogicManager and OwnedOwnerManager constructors: - -Change: -```typescript -const logic = new LogicManager( - d.logic.script, - d.logic.cellDeps, - dao, - ickbUdt, -); -const ownedOwner = new OwnedOwnerManager( - d.ownedOwner.script, - d.ownedOwner.cellDeps, - dao, - ickbUdt, -); -``` - -To: -```typescript -const logic = new LogicManager(d.logic.script, d.logic.cellDeps, dao); -const ownedOwner = new OwnedOwnerManager( - d.ownedOwner.script, - d.ownedOwner.cellDeps, - dao, -); -``` - -The OrderManager line already passes `ickbUdt.script` (from Phase 4). - -**Step 6: Audit SDK and apps for ErrorTransactionInsufficientCoin catch blocks** - -Run: `grep -r "ErrorTransactionInsufficientCoin" packages/sdk/ apps/` and confirm zero catch blocks exist. RESEARCH.md already found zero catch blocks across the entire codebase (the error was only thrown, never caught). Document this finding: `ErrorUdtInsufficientCoin` is CCC's responsibility -- it surfaces to callers unchanged from `completeInputsByBalance`. No SDK-side migration of catch blocks is needed. - -If any catch blocks ARE found (unexpected), replace `ErrorTransactionInsufficientCoin` with `ErrorUdtInsufficientCoin` from `@ckb-ccc/udt` and update the import. - -**Step 7: Run `pnpm check:full`** - -This validates the entire stack compiles: all 5 library packages with strict TypeScript settings. This is the final gate for Phase 5. - -If `pnpm check:full` fails, investigate and fix the errors. Common issues: -- Missing catalog entry for `@ckb-ccc/udt` (should be added in Plan 05-01) -- Type mismatch on `IckbUdt` constructor parameters -- ScriptDeps import breakage (should not happen -- ScriptDeps is in utils.ts, not udt.ts) - - - cd /workspaces/stack && pnpm check:full - - - - SDK imports IckbUdt (not IckbUdtManager) from @ickb/core - - getConfig() return type uses IckbUdt (not IckbUdtManager) - - IckbUdt constructed with code OutPoints (MAINNET_XUDT_CODE, MAINNET_LOGIC_CODE / testnet equivalents) - - IckbUdt.typeScriptFrom used to compute type script (not hardcoded or from ScriptDeps) - - LogicManager constructed without ickbUdt argument (3 params) - - OwnedOwnerManager constructed without ickbUdt argument (3 params) - - Code OutPoint constants added for both mainnet and testnet - - Devnet path uses cellDeps[0].outPoint as fallback for code OutPoints - - SDK and apps audited for ErrorTransactionInsufficientCoin catch blocks -- zero found, no migration required - - pnpm check:full passes with zero errors across all 5 library packages - - - - - - -1. `pnpm check:full` passes -- all 5 library packages compile with zero type errors -2. `! test -f packages/utils/src/udt.ts` -- udt.ts deleted from utils -3. `! grep -q "udt.js" packages/utils/src/index.ts` -- barrel export removed -4. `grep -r "UdtHandler\|UdtManager\|UdtCell\|findUdts\|addUdts\|isUdtSymbol\|ErrorTransactionInsufficientCoin\|IckbUdtManager" packages/` returns no matches -5. `grep -q "new IckbUdt" packages/sdk/src/constants.ts` -- SDK constructs IckbUdt -6. `grep -q "IckbUdt.typeScriptFrom" packages/sdk/src/constants.ts` -- SDK uses typeScriptFrom -7. `grep -r "udtBalanceFrom" packages/` returns no matches (deprecated API eliminated) -8. `grep -r "getInputsUdtBalance\|getOutputsUdtBalance\|completeInputsByUdt" packages/` returns no matches - - - -- packages/utils/src/udt.ts fully deleted (~406 lines removed) -- UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol no longer exist in codebase -- No deprecated CCC API calls (udtBalanceFrom, getInputsUdtBalance, etc.) remain in any package -- SDK constructs IckbUdt with individual code OutPoints (mainnet + testnet) -- SDK uses IckbUdt.typeScriptFrom to compute type script -- LogicManager and OwnedOwnerManager constructed without ickbUdt argument -- ScriptDeps, ExchangeRatio, ValueComponents preserved (not deleted) -- pnpm check:full passes across all 5 library packages - - - -After completion, create `.planning/phases/05-ickb-core-udt-refactor/05-02-SUMMARY.md` - diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-02-SUMMARY.md b/.planning/phases/05-ickb-core-udt-refactor/05-02-SUMMARY.md deleted file mode 100644 index 636dc52..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-02-SUMMARY.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -phase: 05-ickb-core-udt-refactor -plan: 02 -subsystem: core -tags: [udt, ccc, xudt, ickb, sdk, deletion, code-deps] - -# Dependency graph -requires: - - phase: 05-ickb-core-udt-refactor - plan: 01 - provides: IckbUdt class extending udt.Udt, LogicManager/OwnedOwnerManager without udtHandler -provides: - - Deleted UDT infrastructure from @ickb/utils (~406 lines) - - SDK getConfig() constructing IckbUdt with individual code OutPoints - - Code cell OutPoint constants for mainnet and testnet (xUDT + Logic) -affects: [sdk, bot, apps] - -# Tech tracking -tech-stack: - added: [] - patterns: [IckbUdt constructed with individual code OutPoints, network capture for code OutPoint selection] - -key-files: - created: [] - modified: - - packages/utils/src/index.ts - - packages/sdk/src/constants.ts - deleted: - - packages/utils/src/udt.ts - -key-decisions: - - "IckbUdt.typeScriptFrom computes type script dynamically from raw UDT and Logic scripts (not hardcoded)" - - "Devnet code OutPoints fallback to cellDeps[0].outPoint -- pragmatic since devnet deps are typically depType: code" - - "ErrorTransactionInsufficientCoin had zero catch blocks across entire codebase -- clean deletion with no migration" - -patterns-established: - - "SDK network capture pattern: extract network string before d gets reassigned, use for conditional constants" - - "Code OutPoint constants: hardcoded per-network OutPoints for individual code deps, sourced from deployment.toml" - -requirements-completed: [SMTX-05, SMTX-07, SMTX-10, UDT-04] - -# Metrics -duration: 4min -completed: 2026-02-26 ---- - -# Phase 5 Plan 2: Delete UDT Infrastructure and Wire SDK Summary - -**Deleted UdtHandler/UdtManager/ErrorTransactionInsufficientCoin from @ickb/utils (~406 lines) and rewired SDK to construct IckbUdt with individual xUDT and Logic code OutPoints** - -## Performance - -- **Duration:** 4 min -- **Started:** 2026-02-26T16:16:16Z -- **Completed:** 2026-02-26T16:20:08Z -- **Tasks:** 2 -- **Files modified:** 2 modified, 1 deleted - -## Accomplishments -- Deleted packages/utils/src/udt.ts removing UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol (~406 lines) -- Updated SDK getConfig() to construct IckbUdt with individual code OutPoints (mainnet/testnet) and IckbUdt.typeScriptFrom for script computation -- Removed ickbUdt argument from LogicManager and OwnedOwnerManager construction in SDK -- Added 4 code cell OutPoint constants (mainnet xUDT, mainnet Logic, testnet xUDT, testnet Logic) sourced from deployment.toml -- Confirmed zero ErrorTransactionInsufficientCoin catch blocks across entire codebase -- clean deletion - -## Task Commits - -Each task was committed atomically: - -1. **Task 1: Delete utils/src/udt.ts and update barrel export** - `c5d4363` (refactor) -2. **Task 2: Update SDK getConfig to construct IckbUdt with code OutPoints and verify full stack** - `6400cc4` (feat) - -## Files Created/Modified -- `packages/utils/src/udt.ts` - DELETED: removed ~406 lines of UdtHandler, UdtManager, ErrorTransactionInsufficientCoin, UdtCell, findUdts, addUdts, isUdtSymbol -- `packages/utils/src/index.ts` - Removed "export * from ./udt.js" barrel export -- `packages/sdk/src/constants.ts` - IckbUdt import, code OutPoint constants, IckbUdt construction with typeScriptFrom, LogicManager/OwnedOwnerManager 3-param construction - -## Decisions Made -- Used IckbUdt.typeScriptFrom to compute type script dynamically from raw UDT and Logic scripts, rather than passing d.udt.script directly (which would bypass the correct args computation) -- Devnet fallback uses cellDeps[0].outPoint for code OutPoints -- pragmatic since devnet deps are typically depType: code -- Network string captured before d gets reassigned via `const network = typeof d === "string" ? d : undefined` for clean conditional logic - -## Deviations from Plan - -None - plan executed exactly as written. - -## Issues Encountered -None - -## User Setup Required -None - no external service configuration required. - -## Next Phase Readiness -- Phase 5 complete: IckbUdt replaces all UDT infrastructure, full stack compiles -- All deprecated CCC API calls (udtBalanceFrom, getInputsUdtBalance, etc.) eliminated -- ScriptDeps, ExchangeRatio, ValueComponents preserved for downstream consumers -- Ready for Phase 6 (SDK refactor) or PR preparation - -## Self-Check: PASSED - -All files exist, all commits verified. - ---- -*Phase: 05-ickb-core-udt-refactor* -*Completed: 2026-02-26* diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-CONTEXT.md b/.planning/phases/05-ickb-core-udt-refactor/05-CONTEXT.md deleted file mode 100644 index f970388..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-CONTEXT.md +++ /dev/null @@ -1,84 +0,0 @@ -# Phase 5: @ickb/core UDT Refactor - Context - -**Gathered:** 2026-02-26 -**Status:** Ready for planning - - -## Phase Boundary - -Implement `IckbUdt extends udt.Udt` in `@ickb/core` with `infoFrom` override for multi-representation balance (xUDT + receipts + deposits). Delete `UdtHandler` interface, `UdtManager` class, `ErrorTransactionInsufficientCoin`, `UdtCell`, `findUdts`, `addUdts` from `@ickb/utils`. Remove `udtHandler` parameter from `LogicManager` and `OwnedOwnerManager` (same pattern as Phase 4 OrderManager fix). Replace deprecated CCC API calls in `@ickb/core` and `@ickb/utils`. Update SDK to construct and use `IckbUdt`. - - - - -## Implementation Decisions - -### UDT completion & state compression -- Drop `compressState` feature entirely — CCC's `completeInputsByBalance` handles completion -- Callers use `ickbUdt.completeInputsByBalance(tx, signer)` directly — no convenience wrapper -- Destructure return as needed: `const { tx } = await ickbUdt.completeInputsByBalance(...)` — `addedCount` available but not required -- Trust CCC fully for completion — `infoFrom` provides accurate cell valuations, CCC handles dual-constraint (balance + capacity) optimization -- Stick to `completeInputsByBalance` only — `completeInputsAll` and `completeByTransfer` are inherited but not documented for iCKB callers - -### CellDeps strategy -- IckbUdt overrides `addCellDeps` to add both xUDT code dep AND iCKB Logic code dep (individual `depType: "code"` deps, not dep group) -- Constructor takes `code: OutPointLike` (xUDT script code cell) via base class + `logicCode: OutPointLike` (iCKB Logic script code cell) as new param -- Individual code cell OutPoints sourced from `forks/contracts/` (mainnet + testnet deployments) -- Only IckbUdt switches to code deps pattern in Phase 5; other managers (DaoManager, LogicManager, OrderManager, OwnedOwnerManager) keep `CellDep[]` for now -- Mixed patterns (code deps + dep groups) coexist temporarily — `tx.addCellDeps` deduplicates - -### Cell discovery (findUdts) -- Delete `findUdts`, `addUdts`, `UdtCell` interface, `isUdtSymbol` — all internal to `UdtManager`, no external consumers -- CCC's `completeInputs` (used internally by `completeInputsByBalance`) handles cell discovery via `Udt.filter` -- CCC's `isUdt()` length check (>= 16 bytes) is equivalent to current `>= 34` hex chars — no iCKB-specific reason for old threshold - -### Error reporting -- Accept CCC's `ErrorUdtInsufficientCoin` from `completeInputsByBalance` — callers (SDK, UI) format error messages themselves -- Delete `ErrorTransactionInsufficientCoin` class from `@ickb/utils` -- Plain `Error` throws for header-not-found in `infoFrom` (exceptional path — CCC cache should provide headers) -- Phase 5 handles SDK error handling updates (not deferred to Phase 6) - -### calculateScript → typeScriptFrom -- Renamed to `IckbUdt.typeScriptFrom(udt, ickbLogic)` — static method, CCC-aligned naming -- Keep current parameter types: `(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script` -- Computes the `script` param for IckbUdt constructor (token identity via args) - -### Manager dependency chain -- LogicManager: remove `udtHandler: UdtHandler` constructor param, remove `tx.addCellDeps(this.udtHandler.cellDeps)` calls (2 sites) — UDT cellDeps are caller responsibility -- OwnedOwnerManager: same treatment — remove `udtHandler` param, remove cellDeps calls (2 sites) -- This matches Phase 4's OrderManager pattern exactly -- With all three managers cleaned, `UdtHandler` interface has zero consumers → delete from `@ickb/utils` -- `ScriptDeps` interface: researcher should check if any consumers remain after `UdtHandler` deletion - -### Claude's Discretion -- Constructor parameter for `IckbUdt`: whether to take `CellDep[]` or single `CellDep` for the dep group — Claude picks cleanest pattern -- Internal organization of the `infoFrom` override code -- How to structure the `@ckb-ccc/udt` dependency addition to `@ickb/core` package.json -- Exact migration of SDK `IckbUdtManager` construction to `IckbUdt` construction - - - - -## Specific Ideas - -- CCC Udt's `completeInputsByBalance` capacity handling is more sophisticated than current `completeUdt` — caps capacity at tx fee to avoid over-providing from UDT cells -- CCC's `ErrorUdtInsufficientCoin` has a `reason` field for custom messages — could be used later for iCKB-specific formatting if needed (note for researcher) -- Researcher should check for catch blocks referencing the old `ErrorTransactionInsufficientCoin` class across SDK and apps -- Matching bot scenario: `infoFrom` may be called frequently during order matching. CCC `Client.cache` handles header fetch dedup, but researcher should evaluate if additional caching is needed for high-frequency scenarios -- Individual code cell OutPoints (replacing dep group) can be found in `forks/contracts/` for both mainnet and testnet - - - - -## Deferred Ideas - -- **ValueComponents redesign**: `udtValue` field name is ambiguous in multi-UDT context (which UDT?). CCC's `UdtInfo` scoped to specific Udt instance is cleaner. Evaluate renaming/replacing across all packages in a future phase -- **All managers to code deps**: Switch DaoManager, LogicManager, OrderManager, OwnedOwnerManager from `CellDep[]` to individual code OutPoints (CCC pattern). Phase 5 only migrates IckbUdt -- **infoFrom caching for matching bot**: If matching bot performance becomes a bottleneck, add cell→UdtInfo result caching in IckbUdt to avoid recomputation across trial transactions - - - ---- - -*Phase: 05-ickb-core-udt-refactor* -*Context gathered: 2026-02-26* diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-RESEARCH.md b/.planning/phases/05-ickb-core-udt-refactor/05-RESEARCH.md deleted file mode 100644 index f12f1b8..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-RESEARCH.md +++ /dev/null @@ -1,589 +0,0 @@ -# Phase 5: @ickb/core UDT Refactor - Research - -**Researched:** 2026-02-26 -**Domain:** CCC UDT subclassing, iCKB multi-representation balance, code deps migration -**Confidence:** HIGH - -## Summary - -Phase 5 replaces the custom `IckbUdtManager` (extending `UdtManager`) in `@ickb/core` with `IckbUdt` (extending `udt.Udt` from `@ckb-ccc/udt`). The core challenge is overriding `infoFrom()` to account for iCKB's three on-chain value representations: xUDT cells (positive balance), receipt cells (positive, input only), and deposit cells (negative, input only). The CCC `Udt` class provides all required override points and a complete input-completion pipeline (`completeInputsByBalance`) that consumes the output of `infoFrom`. - -Simultaneously, the phase removes `udtHandler` from `LogicManager` and `OwnedOwnerManager` (matching Phase 4's `OrderManager` pattern), deletes the entire UDT infrastructure from `@ickb/utils` (`UdtHandler`, `UdtManager`, `ErrorTransactionInsufficientCoin`, `UdtCell`, `findUdts`, `addUdts`, `isUdtSymbol`), and migrates the SDK from `IckbUdtManager` to `IckbUdt`. The dep group pattern is replaced with individual code deps (xUDT OutPoint + iCKB Logic OutPoint) for `IckbUdt` only. - -All required code cell OutPoints are available in `forks/contracts/scripts/deployment/` for both mainnet and testnet. The `@ckb-ccc/udt` package is already available via the local CCC fork build (workspace-linked by `.pnpmfile.cjs`). - -**Primary recommendation:** Implement `IckbUdt extends udt.Udt` with `infoFrom` override as the sole customization point. Use the CCC `completeInputsByBalance` pipeline for balance completion. Delete all UDT infrastructure from `@ickb/utils` since `IckbUdt` replaces it entirely. - - -## User Constraints (from CONTEXT.md) - -### Locked Decisions -- Drop `compressState` feature entirely -- CCC's `completeInputsByBalance` handles completion -- Callers use `ickbUdt.completeInputsByBalance(tx, signer)` directly -- no convenience wrapper -- Destructure return as needed: `const { tx } = await ickbUdt.completeInputsByBalance(...)` -- `addedCount` available but not required -- Trust CCC fully for completion -- `infoFrom` provides accurate cell valuations, CCC handles dual-constraint (balance + capacity) optimization -- Stick to `completeInputsByBalance` only -- `completeInputsAll` and `completeByTransfer` are inherited but not documented for iCKB callers -- IckbUdt overrides `addCellDeps` to add both xUDT code dep AND iCKB Logic code dep (individual `depType: "code"` deps, not dep group) -- Constructor takes `code: OutPointLike` (xUDT script code cell) via base class + `logicCode: OutPointLike` (iCKB Logic script code cell) as new param -- Individual code cell OutPoints sourced from `forks/contracts/` (mainnet + testnet deployments) -- Only IckbUdt switches to code deps pattern in Phase 5; other managers (DaoManager, LogicManager, OrderManager, OwnedOwnerManager) keep `CellDep[]` for now -- Mixed patterns (code deps + dep groups) coexist temporarily -- `tx.addCellDeps` deduplicates -- Delete `findUdts`, `addUdts`, `UdtCell` interface, `isUdtSymbol` -- all internal to `UdtManager`, no external consumers -- CCC's `completeInputs` (used internally by `completeInputsByBalance`) handles cell discovery via `Udt.filter` -- CCC's `isUdt()` length check (>= 16 bytes) is equivalent to current `>= 34` hex chars -- no iCKB-specific reason for old threshold -- Accept CCC's `ErrorUdtInsufficientCoin` from `completeInputsByBalance` -- callers (SDK, UI) format error messages themselves -- Delete `ErrorTransactionInsufficientCoin` class from `@ickb/utils` -- Plain `Error` throws for header-not-found in `infoFrom` (exceptional path -- CCC cache should provide headers) -- Phase 5 handles SDK error handling updates (not deferred to Phase 6) -- Renamed to `IckbUdt.typeScriptFrom(udt, ickbLogic)` -- static method, CCC-aligned naming -- Keep current parameter types: `(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script` -- Computes the `script` param for IckbUdt constructor (token identity via args) -- LogicManager: remove `udtHandler: UdtHandler` constructor param, remove `tx.addCellDeps(this.udtHandler.cellDeps)` calls (2 sites) -- UDT cellDeps are caller responsibility -- OwnedOwnerManager: same treatment -- remove `udtHandler` param, remove cellDeps calls (2 sites) -- This matches Phase 4's OrderManager pattern exactly -- With all three managers cleaned, `UdtHandler` interface has zero consumers -> delete from `@ickb/utils` -- `ScriptDeps` interface: researcher should check if any consumers remain after `UdtHandler` deletion - -### Claude's Discretion -- Constructor parameter for `IckbUdt`: whether to take `CellDep[]` or single `CellDep` for the dep group -- Claude picks cleanest pattern -- Internal organization of the `infoFrom` override code -- How to structure the `@ckb-ccc/udt` dependency addition to `@ickb/core` package.json -- Exact migration of SDK `IckbUdtManager` construction to `IckbUdt` construction - -### Deferred Ideas (OUT OF SCOPE) -- **ValueComponents redesign**: `udtValue` field name is ambiguous in multi-UDT context (which UDT?). CCC's `UdtInfo` scoped to specific Udt instance is cleaner. Evaluate renaming/replacing across all packages in a future phase -- **All managers to code deps**: Switch DaoManager, LogicManager, OrderManager, OwnedOwnerManager from `CellDep[]` to individual code OutPoints (CCC pattern). Phase 5 only migrates IckbUdt -- **infoFrom caching for matching bot**: If matching bot performance becomes a bottleneck, add cell->UdtInfo result caching in IckbUdt to avoid recomputation across trial transactions - - - -## Phase Requirements - -| ID | Description | Research Support | -|----|-------------|-----------------| -| SMTX-05 | UDT handler registration replaced by direct Udt instance usage | LogicManager/OwnedOwnerManager `udtHandler` removed (4 sites); `UdtHandler` interface deleted; callers pass `ickbUdt.script` to managers and call `ickbUdt.addCellDeps(tx)` externally | -| SMTX-07 | IckbUdtManager multi-representation balance logic preserved | `IckbUdt.infoFrom()` override handles xUDT cells (positive), receipt cells (positive, input only), deposit cells (negative, input only); conservation law preserved via accurate sign conventions | -| SMTX-10 | Deprecated CCC API calls replaced | `ccc.udtBalanceFrom()` calls (3 in `UdtManager`) eliminated by deleting `UdtManager`; `IckbUdtManager.getInputsUdtBalance()` replaced by `IckbUdt.infoFrom()` override; no deprecated APIs remain | -| UDT-04 | IckbUdt extends udt.Udt implemented | `IckbUdt` class with `infoFrom` override, `addCellDeps` override (individual code deps), `typeScriptFrom` static method, LogicManager/OwnedOwnerManager `udtHandler` removed | - - -## Standard Stack - -### Core -| Library | Version | Purpose | Why Standard | -|---------|---------|---------|--------------| -| `@ckb-ccc/udt` | workspace (local CCC fork) | Base `Udt` class for subclassing | CCC's official UDT abstraction; `infoFrom` is the override point for multi-representation balance | -| `@ckb-ccc/core` | catalog: ^1.12.2 | CKB core types, Transaction, Client | Already used across all packages | -| `@ckb-ccc/ssri` | workspace (local CCC fork) | `ssri.Trait` base class (parent of `Udt`) | Transitive dependency; `Udt extends ssri.Trait` provides `code: OutPoint` | - -### Supporting -| Library | Version | Purpose | When to Use | -|---------|---------|---------|-------------| -| `@ickb/dao` | workspace:* | `DaoManager.isDeposit()` for deposit cell identification | Already a dependency of `@ickb/core`; used in `infoFrom` for deposit cell detection | -| `@ickb/utils` | workspace:* | `ExchangeRatio`, `ValueComponents`, `ScriptDeps`, utility functions | Already a dependency; `ScriptDeps` still used by managers after `UdtHandler` deletion | - -### Alternatives Considered -| Instead of | Could Use | Tradeoff | -|------------|-----------|----------| -| Subclass `Udt` | Keep `UdtManager` | Loses CCC's completion pipeline, keeps duplicated code | -| Override `infoFrom` only | Override `getInputsInfo`/`getOutputsInfo` | `infoFrom` is simpler -- single override handles both inputs and outputs | -| Dep group for IckbUdt | Individual code deps | Dep groups semantically imply "all cells in group needed"; CCC author prefers individual code deps | - -**Installation:** -Add `@ckb-ccc/udt` to `@ickb/core/package.json` dependencies. With the local CCC fork build active, `.pnpmfile.cjs` automatically rewires to workspace:*: -```json -{ - "dependencies": { - "@ckb-ccc/core": "catalog:", - "@ckb-ccc/udt": "catalog:", - "@ickb/dao": "workspace:*", - "@ickb/utils": "workspace:*" - } -} -``` - -**Note on catalog:** `@ckb-ccc/udt` is NOT currently in the pnpm-workspace.yaml catalog. It needs to be added OR use `"workspace:*"` directly since the `.pnpmfile.cjs` hook rewires it anyway. Recommendation: add `"@ckb-ccc/udt": "^1.12.2"` to the catalog for consistency with `@ckb-ccc/core`, though the pnpmfile hook will override it to `workspace:*` when the fork is present. - -## Architecture Patterns - -### IckbUdt Class Structure -``` -@ickb/core/src/udt.ts -├── IckbUdt extends udt.Udt -│ ├── constructor(code, script, logicCode, logicScript, daoManager) -│ ├── static typeScriptFrom(udt, ickbLogic): Script -│ ├── override infoFrom(client, cells, acc?): Promise -│ └── override addCellDeps(txLike): Transaction -├── ickbValue(capacity, header): FixedPoint (unchanged) -├── convert(isCkb2Udt, amount, rate, ...): FixedPoint (unchanged) -├── ickbExchangeRatio(header, ...): ExchangeRatio (unchanged) -└── constants (AR_0, ICKB_DEPOSIT_CAP, etc.) (unchanged) -``` - -### Pattern 1: infoFrom Override for Multi-Representation Balance -**What:** Override `infoFrom()` to value three cell types: xUDT (positive), receipts (positive, input only), deposits (negative, input only). -**When to use:** Called by CCC's `getInputsInfo()` and `getOutputsInfo()` which pass resolved cells. -**Key insight:** `infoFrom` receives `CellAnyLike` which may or may not have `outPoint`. Input cells (from `getInputsInfo`) have `outPoint` (needed for header fetches). Output cells (from `getOutputsInfo`) do not have `outPoint` -- receipt and deposit cells should only appear as inputs, so the absence of `outPoint` naturally excludes them from output-side processing. - -```typescript -// Source: Verified from CCC Udt source (forks/ccc/packages/udt/src/udt/index.ts) -import { udt } from "@ckb-ccc/udt"; - -export class IckbUdt extends udt.Udt { - constructor( - code: ccc.OutPointLike, // xUDT code cell OutPoint (via base Trait) - script: ccc.ScriptLike, // iCKB UDT type script (via base Udt) - public readonly logicCode: ccc.OutPoint, // iCKB Logic code cell OutPoint - public readonly logicScript: ccc.Script, // iCKB Logic script - public readonly daoManager: DaoManager, // for isDeposit check - ) { - super(code, script); - } - - async infoFrom( - client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: udt.UdtInfoLike, - ): Promise { - const info = udt.UdtInfo.from(acc).clone(); - - for (const cellLike of [cells].flat()) { - const cell = ccc.CellAny.from(cellLike); - - // Standard xUDT cell -- delegate to base class pattern - if (this.isUdt(cell)) { - info.addAssign({ - balance: udt.Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Receipt and deposit cells need outPoint for header fetch. - // Output cells (no outPoint) are skipped -- correct by design. - if (!cell.outPoint) { - continue; - } - - const { type, lock } = cell.cellOutput; - - // Receipt cell: type === logicScript - if (type && this.logicScript.eq(type)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); - } - const { depositQuantity, depositAmount } = - ReceiptData.decode(cell.outputData); - info.addAssign({ - balance: ickbValue(depositAmount, txWithHeader.header) * - depositQuantity, - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Deposit cell: lock === logicScript AND isDeposit - if (this.logicScript.eq(lock) && this.daoManager.isDeposit(cell)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for txHash"); - } - info.addAssign({ - balance: -ickbValue(cell.capacityFree, txWithHeader.header), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - } - - return info; - } - - override addCellDeps(txLike: ccc.TransactionLike): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - // xUDT code dep (from base class's this.code) - tx.addCellDeps({ outPoint: this.code, depType: "code" }); - // iCKB Logic code dep - tx.addCellDeps({ outPoint: this.logicCode, depType: "code" }); - return tx; - } - - static typeScriptFrom(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script { - const { codeHash, hashType } = udt; - return new ccc.Script( - codeHash, - hashType, - [ickbLogic.hash(), "00000080"].join("") as ccc.Hex, - ); - } -} -``` - -### Pattern 2: Manager udtHandler Removal (Phase 4 Pattern) -**What:** Remove `udtHandler: UdtHandler` constructor parameter and `tx.addCellDeps(this.udtHandler.cellDeps)` calls from `LogicManager` and `OwnedOwnerManager`. -**When to use:** Follows Phase 4's `OrderManager` pattern exactly. -**Example (LogicManager):** -```typescript -// BEFORE: -constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - public readonly udtHandler: UdtHandler, // REMOVE -) {} - -// AFTER: -constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, -) {} - -// BEFORE (in deposit, completeDeposit methods): -tx.addCellDeps(this.udtHandler.cellDeps); // REMOVE (4 sites total: 2 in LogicManager, 2 in OwnedOwnerManager) - -// Caller responsibility (SDK or app code): -tx = ickbUdt.addCellDeps(tx); // Caller adds UDT cellDeps before or after calling manager methods -``` - -### Pattern 3: SDK Construction Migration -**What:** Replace `IckbUdtManager` construction with `IckbUdt` in `getConfig()`. -**Key change:** `getConfig` needs xUDT code OutPoint and iCKB Logic code OutPoint (not dep group). - -```typescript -// BEFORE: -const ickbUdt = new IckbUdtManager( - d.udt.script, // UDT type script - d.udt.cellDeps, // dep group CellDep[] - d.logic.script, // logic script - dao, // DaoManager -); - -// AFTER: -const ickbUdt = new IckbUdt( - udtCode, // xUDT code cell OutPoint - d.udt.script, // UDT type script (computed via typeScriptFrom) - logicCode, // iCKB Logic code cell OutPoint - d.logic.script, // logic script - dao, // DaoManager -); -``` - -### Anti-Patterns to Avoid -- **Overriding `getInputsInfo`/`getOutputsInfo` instead of `infoFrom`:** The Phase 3 decision (03-02) explicitly chose `infoFrom` as the sole override point. `getInputsInfo` and `getOutputsInfo` both delegate to `infoFrom` already. -- **Adding CCC `isUdt()` workaround:** CCC's `isUdt()` checks `>= 16 bytes` data length, which is equivalent to the old `>= 34` hex chars check. No iCKB-specific override needed. -- **Wrapping `completeInputsByBalance`:** The decision explicitly says "no convenience wrapper." Callers use `ickbUdt.completeInputsByBalance(tx, signer)` directly. -- **Keeping `UdtHandler` for backward compatibility:** The interface has zero consumers after LogicManager/OwnedOwnerManager cleanup. Delete it cleanly. - -## Don't Hand-Roll - -| Problem | Don't Build | Use Instead | Why | -|---------|-------------|-------------|-----| -| UDT cell discovery | Custom `findUdts` generator | `Udt.completeInputs` (via `filter`) | CCC handles dedup, pagination, signer address resolution | -| Balance completion pipeline | Custom `completeUdt` | `Udt.completeInputsByBalance` | CCC handles dual-constraint (balance + capacity) optimization, change output, error throwing | -| UDT balance extraction | `ccc.udtBalanceFrom()` | `Udt.balanceFromUnsafe()` | `udtBalanceFrom` is deprecated; `balanceFromUnsafe` is the replacement | -| Insufficient coin error | Custom `ErrorTransactionInsufficientCoin` | CCC's `ErrorUdtInsufficientCoin` | CCC throws it from `completeInputsByBalance`; has `amount`, `type`, `reason` fields | - -**Key insight:** The entire `UdtManager` class (cell finding, balance calculation, input completion, change output) is replaced by CCC's `Udt` class. The only custom code needed is the `infoFrom` override for multi-representation balance. - -## Common Pitfalls - -### Pitfall 1: Receipt/Deposit Cells in Outputs -**What goes wrong:** `infoFrom` accidentally counts receipt or deposit cells in transaction outputs, breaking the conservation law. -**Why it happens:** `getOutputsInfo` also calls `infoFrom`. If `infoFrom` doesn't distinguish inputs from outputs, receipt/deposit cells could be double-counted. -**How to avoid:** Check for `cell.outPoint` existence. Input cells have `outPoint` (resolved by `CellInput.getCell()`). Output cells created by `Array.from(tx.outputCells)` do NOT have `outPoint`. Receipt and deposit cells should only appear as inputs, so checking `outPoint` naturally excludes them from output processing. -**Warning signs:** Balance reported by `getOutputsInfo` includes non-xUDT cell values. - -### Pitfall 2: DaoManager.isDeposit Requires Full Cell -**What goes wrong:** `daoManager.isDeposit(cell)` called on a `CellAny` that hasn't been fully resolved. -**Why it happens:** `CellAny.from(cellLike)` preserves the `outPoint`, `cellOutput`, and `outputData` from the input. `isDeposit` checks `outputData` for the 8-zero-byte DAO deposit marker. -**How to avoid:** `isDeposit` only checks `outputData` format (8 zero bytes = deposit), not headers. It works on any `CellAny`-compatible object as long as `outputData` is present. The `CellAny.from()` factory preserves `outputData` from the `CellAnyLike`, so this works correctly. Verify by checking `DaoManager.isDeposit` signature accepts `CellAny` (or a compatible type). -**Warning signs:** `isDeposit` returns false for valid deposit cells because `outputData` is missing. - -### Pitfall 3: ScriptDeps Interface Consumers After Deletion -**What goes wrong:** `ScriptDeps` interface deleted along with `UdtHandler`, breaking downstream imports. -**Why it happens:** `ScriptDeps` is used by `LogicManager`, `OwnedOwnerManager`, `OrderManager`, `DaoManager`, and `getConfig()` (SDK constants). It has many consumers beyond `UdtHandler`. -**How to avoid:** `ScriptDeps` MUST be preserved. Only `UdtHandler` extends it and is deleted. `ScriptDeps` remains in `@ickb/utils/utils.ts` and continues to be imported by all manager classes. -**Warning signs:** Compilation errors in packages importing `ScriptDeps`. - -### Pitfall 4: Catalog Entry for @ckb-ccc/udt -**What goes wrong:** `pnpm install` fails because `@ckb-ccc/udt` is not in the catalog and `catalog:` specifier is used. -**Why it happens:** Currently only `@ckb-ccc/core` is in the pnpm-workspace.yaml catalog. The `.pnpmfile.cjs` hook rewires to `workspace:*` when the fork is present, but catalog: specifier needs a matching entry. -**How to avoid:** Either add `"@ckb-ccc/udt": "^1.12.2"` to the catalog in `pnpm-workspace.yaml`, OR use `"workspace:*"` directly in `@ickb/core/package.json`. The pnpmfile hook will rewrite either way when forks are present. Using `catalog:` is cleaner for consistency but requires the catalog entry. -**Warning signs:** `pnpm install` errors about unresolved catalog specifier. - -### Pitfall 5: IckbUdt Constructor and ssri.Trait -**What goes wrong:** `IckbUdt` constructor doesn't properly call `super()` with the right arguments. -**Why it happens:** `Udt extends ssri.Trait`, and `Trait` expects `(code: OutPointLike, executor?: Executor)`. The `Udt` constructor is `(code: OutPointLike, script: ScriptLike, config?: UdtConfigLike)`. `IckbUdt` must pass `code` (xUDT OutPoint) and `script` (iCKB UDT type script) to `super()`, plus store `logicCode` and other iCKB-specific params. -**How to avoid:** Keep constructor simple: `super(code, script)` passes xUDT code OutPoint and iCKB type script to base `Udt`. No executor needed (legacy xUDT, not SSRI). Store `logicCode`, `logicScript`, `daoManager` as own properties. -**Warning signs:** `this.code` doesn't point to xUDT code cell; `this.script` doesn't match iCKB UDT type script. - -## Code Examples - -### IckbUdt addCellDeps Override -```typescript -// Source: Verified pattern from CCC Udt.addCellDeps (forks/ccc/packages/udt/src/udt/index.ts:856-863) -override addCellDeps(txLike: ccc.TransactionLike): ccc.Transaction { - const tx = ccc.Transaction.from(txLike); - // xUDT code dep (base class stores this as this.code from ssri.Trait) - tx.addCellDeps({ outPoint: this.code, depType: "code" }); - // iCKB Logic code dep (new param) - tx.addCellDeps({ outPoint: this.logicCode, depType: "code" }); - return tx; -} -``` - -### SDK getConfig Migration -```typescript -// Source: Current SDK constants.ts construction + planned migration - -// NEW: xUDT and Logic code cell OutPoints (from forks/contracts/scripts/deployment/) -const MAINNET_XUDT_CODE = { txHash: "0xc07844ce21b38e4b071dd0e1ee3b0e27afd8d7532491327f39b786343f558ab7", index: "0x0" }; -const MAINNET_LOGIC_CODE = { txHash: "0xd7309191381f5a8a2904b8a79958a9be2752dbba6871fa193dab6aeb29dc8f44", index: "0x0" }; -const TESTNET_XUDT_CODE = { txHash: "0xbf6fb538763efec2a70a6a3dcb7242787087e1030c4e7d86585bc63a9d337f5f", index: "0x0" }; -const TESTNET_LOGIC_CODE = { txHash: "0x9ac989b3355764f76cdce02c69dedb819fdfbcbda49a7db1a2c9facdfdb9a7fe", index: "0x0" }; - -// In getConfig(): -const ickbUdt = new IckbUdt( - d === "mainnet" ? MAINNET_XUDT_CODE : TESTNET_XUDT_CODE, // xUDT code OutPoint - IckbUdt.typeScriptFrom( // iCKB UDT type script - ccc.Script.from(UDT), - ccc.Script.from(ICKB_LOGIC), - ), - d === "mainnet" ? MAINNET_LOGIC_CODE : TESTNET_LOGIC_CODE, // Logic code OutPoint - ccc.Script.from(ICKB_LOGIC), // Logic script - dao, // DaoManager -); -``` - -### Error Handling Migration in SDK -```typescript -// Source: CCC ErrorUdtInsufficientCoin (forks/ccc/packages/udt/src/udt/index.ts:27-83) - -// BEFORE (old pattern): -import { ErrorTransactionInsufficientCoin } from "@ickb/utils"; -try { - // ... -} catch (e) { - if (e instanceof ErrorTransactionInsufficientCoin) { ... } -} - -// AFTER (CCC pattern): -import { ErrorUdtInsufficientCoin } from "@ckb-ccc/udt"; -try { - const { tx } = await ickbUdt.completeInputsByBalance(tx, signer); -} catch (e) { - if (e instanceof ErrorUdtInsufficientCoin) { - // e.amount: shortfall amount - // e.type: UDT type script - // e.message: "Insufficient coin, need {amount} extra coin" - } -} -``` - -### LogicManager After udtHandler Removal -```typescript -// Source: Current logic.ts with modifications applied - -export class LogicManager implements ScriptDeps { - constructor( - public readonly script: ccc.Script, - public readonly cellDeps: ccc.CellDep[], - public readonly daoManager: DaoManager, - // udtHandler REMOVED - ) {} - - async deposit(txLike, depositQuantity, depositAmount, lock, client) { - let tx = ccc.Transaction.from(txLike); - // ... - tx.addCellDeps(this.cellDeps); - // tx.addCellDeps(this.udtHandler.cellDeps); // REMOVED - // ... - } - - completeDeposit(txLike, receipts) { - const tx = ccc.Transaction.from(txLike); - // ... - tx.addCellDeps(this.cellDeps); - // tx.addCellDeps(this.udtHandler.cellDeps); // REMOVED - // ... - } -} -``` - -## State of the Art - -| Old Approach | Current Approach | When Changed | Impact | -|--------------|------------------|--------------|--------| -| `UdtHandler` interface + `UdtManager` class | CCC `udt.Udt` class with `infoFrom` override | Phase 5 | Entire custom UDT infrastructure deleted | -| `ccc.udtBalanceFrom()` (deprecated) | `udt.Udt.balanceFromUnsafe()` | CCC upstream | Deprecated calls eliminated by deleting `UdtManager` | -| `ccc.ErrorTransactionInsufficientCoin` (deprecated) | `udt.ErrorUdtInsufficientCoin` | CCC upstream | New error class with `amount`, `type`, `reason` fields | -| `IckbUdtManager.getInputsUdtBalance()` | `IckbUdt.infoFrom()` (override) | Phase 5 | Single override point handles both inputs and outputs | -| Dep group `CellDep` for all iCKB scripts | Individual code OutPoints for IckbUdt | Phase 5 | xUDT + Logic code deps added individually | -| `IckbUdtManager.calculateScript()` | `IckbUdt.typeScriptFrom()` | Phase 5 | Static method renamed for CCC alignment | - -**Deprecated/outdated:** -- `UdtHandler` interface: Replaced by CCC `udt.Udt` type -- `UdtManager` class: Replaced by CCC `udt.Udt` class (which has same capabilities + completion pipeline) -- `ErrorTransactionInsufficientCoin`: Replaced by `ErrorUdtInsufficientCoin` from `@ckb-ccc/udt` -- `UdtCell` interface, `findUdts`, `addUdts`, `isUdtSymbol`: All internal to `UdtManager`, no external consumers - -## Detailed Code Analysis - -### Files to Modify - -| File | Changes | Lines Affected | -|------|---------|----------------| -| `packages/core/src/udt.ts` | Replace `IckbUdtManager` with `IckbUdt extends udt.Udt`; rename `calculateScript` to `typeScriptFrom` | ~100 lines (rewrite class, keep `ickbValue`, `convert`, `ickbExchangeRatio`, constants) | -| `packages/core/src/logic.ts` | Remove `udtHandler` constructor param; remove 2 `tx.addCellDeps(this.udtHandler.cellDeps)` calls; remove `UdtHandler` import | ~6 lines changed | -| `packages/core/src/owned_owner.ts` | Remove `udtHandler` constructor param; remove 2 `tx.addCellDeps(this.udtHandler.cellDeps)` calls; remove `UdtHandler` import | ~6 lines changed | -| `packages/core/package.json` | Add `@ckb-ccc/udt` dependency | 1 line | -| `packages/utils/src/udt.ts` | Delete entire file | ~406 lines deleted | -| `packages/utils/src/index.ts` | Remove `export * from "./udt.js"` | 1 line | -| `packages/sdk/src/constants.ts` | Rewrite `getConfig()` to construct `IckbUdt`; add code OutPoint constants; adjust `LogicManager`/`OwnedOwnerManager` construction (no `ickbUdt` arg); pass `ickbUdt.script` to `OrderManager` | ~30 lines | -| `packages/sdk/src/sdk.ts` | No changes needed -- SDK uses managers, not UdtHandler directly | 0 lines | - -### ScriptDeps Consumer Audit - -`ScriptDeps` is imported/used in these locations (MUST survive `UdtHandler` deletion): - -| File | Usage | Status | -|------|-------|--------| -| `packages/utils/src/utils.ts` | Interface definition | Keep (canonical location) | -| `packages/core/src/logic.ts` | `LogicManager implements ScriptDeps` | Keep | -| `packages/core/src/owned_owner.ts` | `OwnedOwnerManager implements ScriptDeps` | Keep | -| `packages/order/src/order.ts` | `OrderManager implements ScriptDeps` | Keep | -| `packages/dao/src/dao.ts` | `DaoManager implements ScriptDeps` | Keep | -| `packages/sdk/src/constants.ts` | `getConfig()` param type | Keep | -| `packages/utils/src/udt.ts` | `UdtHandler extends ScriptDeps`, `UdtManager implements UdtHandler` | Deleted with file | - -**Conclusion:** `ScriptDeps` has 6 consumers remaining after `UdtHandler`/`UdtManager` deletion. It MUST be preserved. - -### ExchangeRatio Consumer Audit - -`ExchangeRatio` from `@ickb/utils` is used in: -| File | Usage | -|------|-------| -| `packages/core/src/udt.ts` | `convert()` function parameter type | -| `packages/sdk/src/sdk.ts` | Imported from `@ickb/utils` (indirect via `@ickb/core`) | - -**Conclusion:** `ExchangeRatio` stays in `@ickb/utils/utils.ts`. Not affected by udt.ts deletion. - -### Catch Blocks for ErrorTransactionInsufficientCoin - -Searched across all apps and packages: -- **`packages/`**: Only thrown in `packages/utils/src/udt.ts:258` (inside `UdtManager.completeUdt`). No catch blocks. -- **`apps/`**: No catch blocks referencing `ErrorTransactionInsufficientCoin`. Zero hits. -- **Conclusion:** Deleting the class has no impact on error handling. CCC's `ErrorUdtInsufficientCoin` (thrown by `completeInputsByBalance`) is the only error callers will encounter going forward. - -### Code Cell OutPoints (from forks/contracts/scripts/deployment/) - -| Network | Script | tx_hash | index | -|---------|--------|---------|-------| -| Mainnet | xUDT | `0xc07844ce21b38e4b071dd0e1ee3b0e27afd8d7532491327f39b786343f558ab7` | 0 | -| Mainnet | iCKB Logic | `0xd7309191381f5a8a2904b8a79958a9be2752dbba6871fa193dab6aeb29dc8f44` | 0 | -| Testnet | xUDT | `0xbf6fb538763efec2a70a6a3dcb7242787087e1030c4e7d86585bc63a9d337f5f` | 0 | -| Testnet | iCKB Logic | `0x9ac989b3355764f76cdce02c69dedb819fdfbcbda49a7db1a2c9facdfdb9a7fe` | 0 | - -Source: `forks/contracts/scripts/deployment/mainnet/deployment.toml` and `forks/contracts/scripts/deployment/testnet/deployment.toml` (HIGH confidence -- direct file examination). - -### CCC Udt.infoFrom Signature Details - -```typescript -// From forks/ccc/packages/udt/src/udt/index.ts:624-641 -async infoFrom( - _client: ccc.Client, // Client for network requests (subclasses use it) - cells: ccc.CellAnyLike | ccc.CellAnyLike[], // Single cell or array - acc?: UdtInfoLike, // Optional accumulator for running totals -): Promise -``` - -Key details: -- `_client` parameter: Base class doesn't use it (local-only operation), but it's available for subclass network requests (header fetches in IckbUdt) -- `cells` is flattened with `[cells].flat()` -- accepts single cell or array -- `acc` is optional starting accumulator; `UdtInfo.from(acc).clone()` creates a safe copy -- Returns `UdtInfo` with `{ balance, capacity, count }` fields (all mutable) -- `balance` can go negative (deposit cells subtract) -- this is intentional for conservation law accounting -- CCC's `completeInputsByBalance` uses `infoFrom` as the accumulator in `completeInputs`, checking `info.balance >= 0 && info.capacity >= 0` to stop - -### CCC getInputsInfo Flow - -```typescript -// From forks/ccc/packages/udt/src/udt/index.ts:1099-1108 -async getInputsInfo(client, txLike): Promise { - const tx = ccc.Transaction.from(txLike); - const inputCells = await Promise.all( - tx.inputs.map((input) => input.getCell(client)), // Resolves to Cell (has outPoint) - ); - return this.infoFrom(client, inputCells); // Passes Cell[] to infoFrom -} -``` - -`CellInput.getCell(client)` returns a `Cell` (extends `CellAny`, has guaranteed `outPoint`). So when `infoFrom` is called from `getInputsInfo`, all cells have `outPoint`. When called from `getOutputsInfo`, cells come from `tx.outputCells` which creates `CellAny` without `outPoint`. - -### DaoManager.isDeposit Compatibility - -```typescript -// DaoManager.isDeposit checks cell.outputData for 8 zero bytes (DAO deposit marker) -// It accepts ccc.Cell which extends CellAny -// CellAny.from(cellLike) preserves outputData from CellAnyLike -// So passing CellAny to isDeposit works IF outputData has 8+ bytes -``` - -The `daoManager.isDeposit(cell)` call in `infoFrom` receives a `CellAny`. Need to verify `isDeposit` accepts `CellAny` (not just `Cell`). Checking the `DaoManager.isDeposit` signature: - -```typescript -// From packages/dao/src/dao.ts (Phase 1 migrated signature) -isDeposit(cell: ccc.Cell): boolean -``` - -This takes `ccc.Cell`, not `ccc.CellAny`. Since `Cell extends CellAny`, a `CellAny` is NOT a `Cell`. However, for input cells in `infoFrom`, `getInputsInfo` resolves to `Cell` objects (via `CellInput.getCell()`), so this works for inputs. For output cells, we skip deposit detection (no `outPoint` check gates it). This is correct by design -- deposits only appear as inputs. - -## Open Questions - -1. **getConfig devnet path** - - What we know: `getConfig()` accepts a devnet object with `ScriptDeps` for each script. Phase 5 changes IckbUdt construction from `ScriptDeps` (script + cellDeps) to code OutPoints. - - What's unclear: The devnet path provides `{ udt: ScriptDeps, logic: ScriptDeps, ... }`. With `IckbUdt` needing code OutPoints instead of `CellDep[]`, the devnet interface needs adjustment. The `udt` entry would need to provide an OutPoint (for xUDT code cell) instead of `cellDeps`. - - Recommendation: For devnet, accept either: (a) a new `codeOutPoint` field in each ScriptDeps-like config, or (b) restructure the devnet config type to match the new needs. Since devnet usage is secondary, keep it minimal -- document the interface change. - -2. **pnpm-workspace.yaml catalog entry** - - What we know: `@ckb-ccc/core` has `catalog:` entry; `@ckb-ccc/udt` does not. - - What's unclear: Whether to add `@ckb-ccc/udt` to catalog or use `workspace:*` directly. - - Recommendation: Add `"@ckb-ccc/udt": "^1.12.2"` to catalog alongside `@ckb-ccc/core` for consistency. The pnpmfile hook rewrites to `workspace:*` when forks are present. - -## Sources - -### Primary (HIGH confidence) -- CCC `Udt` class source: `/workspaces/stack/forks/ccc/packages/udt/src/udt/index.ts` -- `infoFrom`, `addCellDeps`, `completeInputsByBalance`, `getInputsInfo`, `getOutputsInfo` signatures and implementations verified -- CCC `ssri.Trait` source: `/workspaces/stack/forks/ccc/packages/ssri/src/trait.ts` -- constructor `(code: OutPointLike, executor?: Executor)` verified -- CCC `CellAny` class: `/workspaces/stack/forks/ccc/packages/core/src/ckb/transaction.ts:313-432` -- `outPoint` optional, `capacityFree` getter verified -- CCC `ErrorUdtInsufficientCoin`: `/workspaces/stack/forks/ccc/packages/udt/src/udt/index.ts:27-83` -- `amount`, `type`, `reason` fields verified -- Current `IckbUdtManager`: `/workspaces/stack/packages/core/src/udt.ts` -- full source examined -- Current `UdtManager`/`UdtHandler`: `/workspaces/stack/packages/utils/src/udt.ts` -- full source examined -- Current `LogicManager`: `/workspaces/stack/packages/core/src/logic.ts` -- `udtHandler` usage at 2 sites confirmed -- Current `OwnedOwnerManager`: `/workspaces/stack/packages/core/src/owned_owner.ts` -- `udtHandler` usage at 2 sites confirmed -- SDK `getConfig()`: `/workspaces/stack/packages/sdk/src/constants.ts` -- construction flow verified -- Contract deployments: `/workspaces/stack/forks/contracts/scripts/deployment/mainnet/deployment.toml` and testnet equivalent -- xUDT and Logic code cell OutPoints verified - -### Secondary (MEDIUM confidence) -- Phase 3 decision document: `.planning/phases/03-ccc-udt-integration-investigation/03-DECISION.md` -- `infoFrom` as sole override point, cell discovery boundary -- Phase 4 context/execution: `.planning/phases/04-deprecated-ccc-api-replacement/` -- OrderManager pattern for udtHandler removal -- Project STATE.md accumulated decisions -- cross-referenced with source code - -## Metadata - -**Confidence breakdown:** -- Standard stack: HIGH -- all libraries verified from local source code; `@ckb-ccc/udt` available via workspace -- Architecture: HIGH -- `infoFrom` override pattern verified from CCC source; all 4 `udtHandler` removal sites identified and confirmed -- Pitfalls: HIGH -- `outPoint` availability, `ScriptDeps` consumers, catalog entry all verified against source - -**Research date:** 2026-02-26 -**Valid until:** 2026-03-26 (stable -- all source code is local, no external API changes expected) diff --git a/.planning/phases/05-ickb-core-udt-refactor/05-VERIFICATION.md b/.planning/phases/05-ickb-core-udt-refactor/05-VERIFICATION.md deleted file mode 100644 index 0d863ec..0000000 --- a/.planning/phases/05-ickb-core-udt-refactor/05-VERIFICATION.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -phase: 05-ickb-core-udt-refactor -verified: 2026-02-26T17:00:00Z -status: passed -score: 8/8 must-haves verified -re_verification: false ---- - -# Phase 5: @ickb/core UDT Refactor Verification Report - -**Phase Goal:** Implement `IckbUdt extends udt.Udt` in `@ickb/core`, replacing `IckbUdtManager`. Delete entire UDT infrastructure from `@ickb/utils`. Wire SDK to construct `IckbUdt`. -**Verified:** 2026-02-26T17:00:00Z -**Status:** passed -**Re-verification:** No — initial verification - -## Goal Achievement - -### Observable Truths - -| # | Truth | Status | Evidence | -|----|-------|--------|----------| -| 1 | `IckbUdt extends udt.Udt` exists in `@ickb/core` with `infoFrom` override | VERIFIED | `packages/core/src/udt.ts` line 20: `export class IckbUdt extends udt.Udt`, line 84: `override async infoFrom` | -| 2 | `infoFrom` correctly values xUDT cells (positive), receipt cells (positive, input only), deposit cells (negative, input only) | VERIFIED | xUDT: `udt.Udt.balanceFromUnsafe` (line 97); receipt: `ickbValue(depositAmount, ...) * depositQuantity` (lines 124-128); deposit: `-ickbValue(cell.capacityFree, ...)` (lines 146-149); output cells gated by `!cell.outPoint` check (line 106) | -| 3 | `IckbUdt.addCellDeps` overridden to add individual code deps | VERIFIED | `packages/core/src/udt.ts` line 168: `override addCellDeps`; adds xUDT code dep (line 171) and Logic code dep (line 173) with `depType: "code"` | -| 4 | `IckbUdt.typeScriptFrom` static method computes iCKB UDT type script | VERIFIED | `packages/core/src/udt.ts` line 57: `static typeScriptFrom(udt: ccc.Script, ickbLogic: ccc.Script): ccc.Script` | -| 5 | `LogicManager` and `OwnedOwnerManager` no longer take `udtHandler` parameter; no `tx.addCellDeps(this.udtHandler.cellDeps)` calls remain | VERIFIED | `logic.ts` constructor has 3 params (script, cellDeps, daoManager); `owned_owner.ts` constructor has 3 params; grep confirms zero `udtHandler` references across both files | -| 6 | `UdtHandler`, `UdtManager`, `ErrorTransactionInsufficientCoin`, `UdtCell`, `findUdts`, `addUdts`, `isUdtSymbol` deleted from `@ickb/utils` | VERIFIED | `packages/utils/src/udt.ts` deleted; `packages/utils/src/index.ts` has no `udt.js` export; grep across all packages confirms zero references | -| 7 | SDK constructs `IckbUdt` with individual code OutPoints; passes `ickbUdt.script` to `OrderManager` | VERIFIED | `packages/sdk/src/constants.ts` line 3: `import { IckbUdt, ... }`, line 63: `new IckbUdt(...)` with `MAINNET_XUDT_CODE`/`TESTNET_XUDT_CODE` and `MAINNET_LOGIC_CODE`/`TESTNET_LOGIC_CODE`; line 86: `OrderManager(d.order.script, d.order.cellDeps, ickbUdt.script)` | -| 8 | `pnpm check:full` passes | VERIFIED | Exit code 0; all 5 library packages lint, build, and test clean | - -**Score:** 8/8 truths verified - -### Required Artifacts - -| Artifact | Expected | Status | Details | -|----------|----------|--------|---------| -| `packages/core/src/udt.ts` | IckbUdt class extending udt.Udt with infoFrom, addCellDeps, typeScriptFrom | VERIFIED | 249 lines; `class IckbUdt extends udt.Udt` at line 20; all three overrides present | -| `packages/core/src/logic.ts` | LogicManager without udtHandler parameter | VERIFIED | Constructor at line 28-32: 3 params only; zero `udtHandler` references | -| `packages/core/src/owned_owner.ts` | OwnedOwnerManager without udtHandler parameter | VERIFIED | Constructor at line 23-27: 3 params only; zero `udtHandler` references | -| `packages/core/package.json` | `@ckb-ccc/udt` dependency | VERIFIED | Line 57: `"@ckb-ccc/udt": "catalog:"` | -| `pnpm-workspace.yaml` | Catalog entry for `@ckb-ccc/udt` | VERIFIED | Line 16: `"@ckb-ccc/udt": ^1.12.2` | -| `packages/utils/src/udt.ts` | Deleted | VERIFIED | File does not exist; confirmed by `test -f` returning false | -| `packages/utils/src/index.ts` | Barrel export without `udt.js` | VERIFIED | 3 lines only: codec.js, heap.js, utils.js | -| `packages/sdk/src/constants.ts` | `getConfig()` constructing `IckbUdt` with code OutPoints | VERIFIED | `new IckbUdt(` at line 63; `IckbUdt.typeScriptFrom` at line 69; 4 code OutPoint constants added (lines 168-202) | - -### Key Link Verification - -| From | To | Via | Status | Details | -|------|----|-----|--------|---------| -| `packages/core/src/udt.ts` | `@ckb-ccc/udt` | `import { udt } from '@ckb-ccc/udt'` | WIRED | Line 2: exact import; `udt.Udt`, `udt.UdtInfo`, `udt.UdtInfoLike` all used | -| `packages/core/src/udt.ts` | `packages/core/src/entities.ts` | `ReceiptData.decode` for receipt cell valuation | WIRED | Line 3: `import { ReceiptData }`, line 122: `ReceiptData.decode(cell.outputData)` | -| `packages/core/src/udt.ts` | `@ickb/dao` | `daoManager.isDeposit` for deposit cell identification | WIRED | Line 4: `import type { DaoManager }`, line 137: `this.daoManager.isDeposit(cell as ccc.Cell)` | -| `packages/sdk/src/constants.ts` | `packages/core/src/udt.ts` | `import { IckbUdt }` and constructor call | WIRED | Line 2: `import { IckbUdt, ... } from "@ickb/core"`, line 63: `new IckbUdt(...)` | -| `packages/sdk/src/constants.ts` | `packages/core/src/udt.ts` | `IckbUdt.typeScriptFrom` for script computation | WIRED | Line 69: `IckbUdt.typeScriptFrom(ccc.Script.from(d.udt.script), ccc.Script.from(d.logic.script))` | - -### Requirements Coverage - -| Requirement | Source Plan | Description | Status | Evidence | -|-------------|------------|-------------|--------|----------| -| SMTX-05 | 05-01, 05-02 | UDT handler registration replaced by direct Udt instance usage | SATISFIED | LogicManager/OwnedOwnerManager no longer take `udtHandler`; UdtHandler/UdtManager/etc deleted from utils; SDK uses `IckbUdt` instance | -| SMTX-07 | 05-01, 05-02 | IckbUdtManager multi-representation UDT balance logic survives intact | SATISFIED | `IckbUdt.infoFrom` handles xUDT (positive), receipts (positive via `ickbValue`), deposits (negative via `ickbValue`); conservation law encoded in sign conventions | -| SMTX-10 | 05-01, 05-02 | Deprecated CCC API calls replaced | SATISFIED | grep confirms zero `udtBalanceFrom`, `getInputsUdtBalance`, `getOutputsUdtBalance`, `completeInputsByUdt` across all packages | -| UDT-04 | 05-01, 05-02 | `IckbUdt extends udt.Udt` with infoFrom, addCellDeps, typeScriptFrom; managers cleaned | SATISFIED | Full implementation verified; `typeScriptFrom` replaces `calculateScript`; all 4 manager `udtHandler.cellDeps` call sites removed | - -All 4 requirements from plan frontmatter are satisfied. No orphaned requirements found (no additional Phase 5 requirements in REQUIREMENTS.md traceability table beyond those declared). - -### Anti-Patterns Found - -No anti-patterns detected in modified files: -- No TODO/FIXME/HACK/PLACEHOLDER comments -- No empty return stubs (`return null`, `return {}`, etc.) -- No console-only handlers -- All method overrides have substantive implementations - -| File | Line | Pattern | Severity | Impact | -|------|------|---------|----------|--------| -| — | — | — | — | No issues found | - -### Human Verification Required - -None required. All success criteria are verifiable through static code analysis and `pnpm check:full`. - -The following items are noted as runtime-only and untestable without a live CKB node, but they are architectural/wiring correct: - -1. **`infoFrom` header fetch correctness** — The `client.getTransactionWithHeader(cell.outPoint.txHash)` calls fetch headers correctly only when connected to a real CKB RPC. Static analysis confirms the call pattern matches Phase 1's established pattern (replacing `getHeader()`). No human action needed for phase acceptance; this is a runtime concern for Phase 6/7. - -### Gaps Summary - -No gaps found. All 8 observable truths are verified. The phase goal is fully achieved: - -- `IckbUdt extends udt.Udt` is implemented with a substantive `infoFrom` override that handles all three iCKB cell representations -- `addCellDeps` adds individual code deps (not dep group) as specified -- `typeScriptFrom` static method correctly computes the UDT type script -- All `udtHandler` references removed from `LogicManager` and `OwnedOwnerManager` -- The entire UDT infrastructure (`UdtHandler`, `UdtManager`, `ErrorTransactionInsufficientCoin`, `UdtCell`, `findUdts`, `addUdts`, `isUdtSymbol`) is deleted from `@ickb/utils` -- SDK wiring is complete: `IckbUdt` constructed with correct code OutPoints for mainnet and testnet; `IckbUdt.typeScriptFrom` used for script computation; `LogicManager` and `OwnedOwnerManager` constructed without `ickbUdt` -- `pnpm check:full` passes with exit code 0 (both `check:fresh` and `check:ci` stages) - ---- - -_Verified: 2026-02-26T17:00:00Z_ -_Verifier: AI Coworker (gsd-verifier)_ diff --git a/.planning/research/ARCHITECTURE.md b/.planning/research/ARCHITECTURE.md deleted file mode 100644 index d1f0a8e..0000000 --- a/.planning/research/ARCHITECTURE.md +++ /dev/null @@ -1,545 +0,0 @@ -# Architecture Research - -**Domain:** CCC-based blockchain library suite refactoring (iCKB protocol) -**Researched:** 2026-02-21 -**Confidence:** HIGH - -## Standard Architecture - -### System Overview - -``` -+-------------------------------------------------------------------+ -| Application Layer | -| +----------+ +----------+ +----------+ +---------+ +--------+ | -| | bot | | interface | | tester | | faucet | | sampler| | -| | (Lumos) | | (Lumos) | | (Lumos) | | (CCC) | | (CCC) | | -| +----+-----+ +----+-----+ +----+-----+ +----+----+ +---+----+ | -| | | | | | | -+-------+--------------+--------------+-------------+------------+----+ - | -+-------------------------------------------------------------------+ -| SDK Composition Layer | -| +---------------------------------------------------------------+ | -| | @ickb/sdk (IckbSdk) | | -| | estimate() | maturity() | request() | collect() | getL1State | | -| +---------------------------------------------------------------+ | -| | | | | | -+-------+--------------+--------------+-------------+-----------------+ -| Domain Layer | -| +-----------+ +---------------+ +--------------------+ | -| | @ickb/dao | | @ickb/order | | @ickb/core | | -| | DaoManager| | OrderManager | | LogicManager | | -| | | | OrderMatcher | | OwnedOwnerManager | | -| | | | | | IckbUdtManager | | -| +-----------+ +---------------+ +--------------------+ | -| | | | | | -+-------+--------------+--------------+-------------+-----------------+ -| Utilities Layer | -| +---------------------------------------------------------------+ | -| | @ickb/utils | | -| | SmartTransaction | CapacityManager | UdtManager | UdtHandler | | -| | collect() | unique() | binarySearch() | MinHeap | | -| +---------------------------------------------------------------+ | -| | | -+------------------------------+--------------------------------------+ -| Foundation Layer | -| +---------------------------------------------------------------+ | -| | @ckb-ccc/core | | -| | Transaction | Client | Signer | Script | Epoch | Molecule | | -| +---------------------------------------------------------------+ | -| +---------------------------------------------------------------+ | -| | @ckb-ccc/udt (CCC's Udt class) | | -| | Udt | UdtInfo | completeInputsByBalance | completeBy | | -| +---------------------------------------------------------------+ | -+-------------------------------------------------------------------+ -``` - -### Component Responsibilities - -| Component | Responsibility | Communicates With | -|-----------|---------------|-------------------| -| `@ickb/utils` | Transaction building, capacity management, generic UDT handling, shared utilities | `@ckb-ccc/core` | -| `@ickb/dao` | NervosDAO deposit/withdrawal/request operations, DaoCell wrapping | `@ickb/utils`, `@ckb-ccc/core` | -| `@ickb/order` | Limit order minting/matching/melting, order cell management, exchange ratio math | `@ickb/utils`, `@ckb-ccc/core` | -| `@ickb/core` | iCKB protocol logic: deposits, receipts, owned-owner pairing, iCKB UDT calculations | `@ickb/dao`, `@ickb/utils`, `@ckb-ccc/core` | -| `@ickb/sdk` | Composes all domain managers into a high-level facade. System state fetching, conversion estimates, order lifecycle | All `@ickb/*` packages | -| Apps | User-facing applications consuming the SDK | `@ickb/sdk` (or individual packages) | - -## Recommended Architecture After Refactoring - -### Target: Remove SmartTransaction, Adopt CCC Udt - -The refactored architecture replaces `SmartTransaction` (a subclass of `ccc.Transaction`) with plain `ccc.Transaction` plus utility functions, and replaces the local `UdtHandler`/`UdtManager` with CCC's `Udt` class (possibly subclassed for iCKB). - -``` -+-------------------------------------------------------------------+ -| Application Layer | -| +----------+ +----------+ +----------+ +---------+ +--------+ | -| | bot | | interface | | tester | | faucet | | sampler| | -| | (CCC) | | (CCC) | | (CCC) | | (CCC) | | (CCC) | | -| +----+-----+ +----+-----+ +----+-----+ +----+----+ +---+----+ | -| | | | | | | -+-------+--------------+--------------+-------------+------------+----+ - | -+-------------------------------------------------------------------+ -| SDK Composition Layer | -| +---------------------------------------------------------------+ | -| | @ickb/sdk (IckbSdk) | | -| | estimate() | maturity() | request() | collect() | getL1State | | -| | Uses: ccc.Transaction (plain) + utility functions | | -| +---------------------------------------------------------------+ | -| | | | | | -+-------+--------------+--------------+-------------+-----------------+ -| Domain Layer | -| +-----------+ +---------------+ +--------------------+ | -| | @ickb/dao | | @ickb/order | | @ickb/core | | -| | DaoManager| | OrderManager | | LogicManager | | -| | | | OrderMatcher | | OwnedOwnerManager | | -| | | | | | IckbUdt (extends | | -| | | | | | ccc Udt) | | -| +-----------+ +---------------+ +--------------------+ | -| | | | | | -+-------+--------------+--------------+-------------+-----------------+ -| Utilities Layer | -| +---------------------------------------------------------------+ | -| | @ickb/utils | | -| | collect() | unique() | binarySearch() | MinHeap | | -| | (NO SmartTransaction, NO UdtHandler, NO UdtManager, | | -| | NO CapacityManager, NO getHeader()/HeaderKey) | | -| +---------------------------------------------------------------+ | -| | | -+------------------------------+--------------------------------------+ -| Foundation Layer | -| +---------------------------------------------------------------+ | -| | @ckb-ccc/core + @ckb-ccc/udt | | -| | Transaction (with completeFee, completeInputsByCapacity) | | -| | Udt (with completeInputsByBalance, completeBy, infoFrom) | | -| | Client | Signer | Script | Epoch | Molecule | | -| +---------------------------------------------------------------+ | -+-------------------------------------------------------------------+ -``` - -### Key Architectural Changes - -**1. SmartTransaction Removal** - -Current state: `SmartTransaction extends ccc.Transaction` adding: -- `udtHandlers: Map` for tracking UDT balancing -- `headers: Map` for header caching -- Overrides `completeFee()` to call UDT handlers first -- Overrides `getInputsUdtBalance()`/`getOutputsUdtBalance()` to delegate to handlers -- Overrides `getInputsCapacity()` to account for DAO withdrawal profit - -Target: All manager methods accept `ccc.TransactionLike` instead of `SmartTransaction` (following CCC's convention: TransactionLike input, Transaction output). Each concern migrates to a different place: - -| SmartTransaction feature | Replacement | -|---|---| -| `udtHandlers` map + `addUdtHandlers()` | CCC `Udt.completeBy()` / `Udt.completeInputsByBalance()` called at transaction completion time | -| `completeFee()` override that calls UDT handlers | App-level orchestration: call `ickbUdt.completeBy(tx, signer)` then `tx.completeFeeBy(signer)` | -| `getInputsUdtBalance()`/`getOutputsUdtBalance()` overrides | `ickbUdt.getInputsInfo(client, tx)` / `ickbUdt.getOutputsInfo(client, tx)` (delegating to overridden `infoFrom()`) | -| `getInputsCapacity()` DAO profit override | Not needed -- CCC's `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` -> `Cell.getDaoProfit()` | -| `headers` map + `addHeaders()` + `getHeader()` | Removed entirely. `getHeader()` call sites inline CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`). `addHeaders()` call sites push to `tx.headerDeps` directly. CCC's Client Cache handles caching transparently | -| `addCellDeps()` deduplication | `tx.addCellDeps()` (already on `ccc.Transaction`) | -| `SmartTransaction.default()` | `ccc.Transaction.default()` | - -**2. CCC Udt Adoption for iCKB** - -CCC's `Udt` class (from `@ckb-ccc/udt`) provides: -- `isUdt(cell)` -- checks type script match + data length >= 16 -- `getInputsInfo(client, tx)` / `getOutputsInfo(client, tx)` -- returns `UdtInfo { balance, capacity, count }` -- `completeInputsByBalance(tx, signer)` -- adds UDT inputs to cover outputs -- `completeBy(tx, signer)` -- complete with change to signer's recommended address -- `completeChangeToLock(tx, signer, lock)` -- complete with change to specific lock -- `balanceFrom(client, cells)` -- extract balance from cells -- `infoFrom(client, cells, acc)` -- extract and accumulate UDT info from cells - -iCKB's triple-representation value requires custom balance calculation to account for: -1. Standard xUDT cells (balance from first 16 bytes of output data) -- standard Udt behavior -2. Receipt cells (valued as `depositQuantity * ickbValue(depositAmount, header)`) -3. iCKB deposit cells consumed as inputs (negative iCKB value: `-ickbValue(cell.capacityFree, header)`) - -**Recommended approach: Subclass `Udt` as `IckbUdt`, overriding `infoFrom()`.** - -The `infoFrom()` method is called by both `getInputsInfo()` and `getOutputsInfo()`, so overriding it propagates to all balance/info methods. Input cells (from `getInputsInfo` → `CellInput.getCell()`) always have `outPoint` set, enabling header fetches for receipt/deposit value calculation. Output cells (from `getOutputsInfo` → `tx.outputCells`) lack `outPoint`, allowing `infoFrom` to distinguish inputs from outputs. `CellAny` has `capacityFree` for deposit cell valuation. - -```typescript -// packages/core/src/udt.ts -- refactored -import { udt } from "@ckb-ccc/udt"; - -export class IckbUdt extends udt.Udt { - constructor( - code: ccc.OutPointLike, - script: ccc.ScriptLike, - public readonly logicScript: ccc.Script, - public readonly daoManager: DaoManager, - config?: udt.UdtConfigLike | null, - ) { - super(code, script, config); - } - - override async infoFrom( - client: ccc.Client, - cells: ccc.CellAnyLike | ccc.CellAnyLike[], - acc?: udt.UdtInfoLike, - ): Promise { - const info = udt.UdtInfo.from(acc).clone(); - - for (const cellLike of [cells].flat()) { - const cell = ccc.CellAny.from(cellLike); - const { type, lock } = cell.cellOutput; - - // Standard xUDT cell -- delegate to base class logic - if (this.isUdt(cell)) { - info.addAssign({ - balance: udt.Udt.balanceFromUnsafe(cell.outputData), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Only input cells (with outPoint) can be receipt/deposit cells - if (!cell.outPoint) { - continue; - } - - // Receipt cell: type === logicScript - if (type?.eq(this.logicScript)) { - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for receipt cell"); - } - const { depositQuantity, depositAmount } = - ReceiptData.decode(cell.outputData); - info.addAssign({ - balance: ickbValue(depositAmount, txWithHeader.header) * depositQuantity, - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - - // Deposit cell: lock === logicScript && isDeposit - if (lock.eq(this.logicScript)) { - const fullCell = ccc.Cell.from({ - outPoint: cell.outPoint, cellOutput: cell.cellOutput, outputData: cell.outputData, - }); - if (!this.daoManager.isDeposit(fullCell)) { - continue; - } - const txWithHeader = await client.getTransactionWithHeader( - cell.outPoint.txHash, - ); - if (!txWithHeader?.header) { - throw new Error("Header not found for deposit cell"); - } - // Deposits SUBTRACT from iCKB balance (conservation law) - info.addAssign({ - balance: -ickbValue(cell.capacityFree, txWithHeader.header), - capacity: cell.cellOutput.capacity, - count: 1, - }); - continue; - } - } - - return info; - } -} -``` - -This approach works because: -- CCC's `Udt.completeInputsByBalance()` chains through `getInputsInfo()` → `infoFrom()` -- overriding `infoFrom` changes balancing behavior without duplicating cell resolution logic -- CCC's `Udt.getBalanceBurned()` delegates to `getInputsBalance()` - `getOutputsBalance()` which chain through `infoFrom()` -- so the conservation law check naturally accounts for all three representations -- The `completeBy()` and `completeChangeToLock()` methods automatically work with the overridden balance calculation -- Input cells have `outPoint` set (resolved via `CellInput.getCell(client)` in `getInputsInfo`), enabling header fetching for receipt/deposit value calculation within `infoFrom` - -**3. DAO Capacity Calculation** - -`SmartTransaction.getInputsCapacity()` is currently overridden to add DAO withdrawal profit. **This override is no longer needed** — CCC's `Transaction.getInputsCapacity()` already handles DAO profit natively via `getInputsCapacityExtra()` -> `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()` (verified from CCC source, see STACK.md lines 116-132). No standalone utility function is required; simply removing the override and using the base `ccc.Transaction.getInputsCapacity()` is sufficient. - -### Component Boundaries After Refactoring - -| Component | Owns | Does NOT Own | -|-----------|------|-------------| -| `@ickb/utils` | `collect()`, `unique()`, `binarySearch()`, `MinHeap`, `BufferedGenerator`, codec utilities | No SmartTransaction, no UdtHandler, no UdtManager, no CapacityManager, no `getHeader()`/`HeaderKey` (all removed; CCC equivalents used directly) | -| `@ickb/dao` | `DaoManager` (deposit/withdraw/requestWithdrawal/find operations), `DaoCell` wrapping | No UDT concerns, no DAO capacity utility (CCC handles natively) | -| `@ickb/order` | `OrderManager` (convert/mint/match/melt/find), `OrderMatcher`, `OrderCell`/`MasterCell`/`OrderGroup`, `Info`/`Ratio`/`OrderData` entities | No direct UDT balancing (delegates to UDT handler) | -| `@ickb/core` | `LogicManager` (deposit/completeDeposit/findReceipts/findDeposits), `OwnedOwnerManager`, `IckbUdt extends udt.Udt` (triple-representation balancing), iCKB exchange rate math | No generic UDT handling | -| `@ickb/sdk` | `IckbSdk` facade, `SystemState`, config/constants, pool snapshot codec. Orchestrates all managers. | No direct cell operations | - -## Data Flow - -### Transaction Building Flow (Post-Refactoring) - -``` -App creates: tx = ccc.Transaction.default() - | - v -Manager operations (domain layer): - orderManager.mint(tx, lock, info, amounts) // Adds outputs, cellDeps - logicManager.deposit(tx, qty, amount, lock) // Adds DAO outputs, receipt - daoManager.requestWithdrawal(tx, deposits, lock) // Adds inputs/outputs - | - v -UDT completion (IckbUdt): - ickbUdt.completeBy(tx, signer) // Adds UDT inputs + change - | - v -Fee completion (ccc.Transaction): - tx.completeFeeBy(signer) // Adds capacity inputs + change - | - v -Sign and send: - signer.sendTransaction(tx) -``` - -### iCKB Value Conservation Flow - -``` -Input UDT + Input Receipts = Output UDT + Input Deposits - -getInputsInfo(): - For each input cell: - if xUDT cell -> balance += UDT amount (16 bytes LE) - if receipt cell -> balance += qty * ickbValue(amount, depositHeader) - if deposit cell -> balance -= ickbValue(capacityFree, depositHeader) - (deposits consumed as inputs reduce UDT balance) - -getOutputsInfo(): - For each output cell: - if xUDT cell -> balance += UDT amount (16 bytes LE) - (receipts and deposits are NOT counted in outputs because - they are tracked by the contract's conservation law) -``` - -### State Discovery Flow - -``` -IckbSdk.getL1State(client, locks): - | - +-> client.getTipHeader() -> tip header - +-> ickbExchangeRatio(tip) -> exchange ratio - | - +-> Parallel: - | +-> getCkb(client, tip) -> ckbAvailable, ckbMaturing - | +-> order.findOrders(client) -> all order groups - | +-> client.getFeeRate() -> fee rate - | - +-> Filter orders into user/system - +-> Estimate maturity for user orders - | - v - SystemState { feeRate, tip, exchangeRatio, orderPool, ckbAvailable, ckbMaturing } -``` - -### Manager Method Signatures (Before vs After) - -**Before (SmartTransaction):** -```typescript -// All managers require SmartTransaction -daoManager.deposit(tx: SmartTransaction, capacities, lock): void -orderManager.mint(tx: SmartTransaction, lock, info, amounts): void -logicManager.deposit(tx: SmartTransaction, qty, amount, lock): void -``` - -**After (plain ccc.TransactionLike / ccc.Transaction):** -```typescript -// All managers accept ccc.TransactionLike, return ccc.Transaction (CCC convention) -daoManager.deposit(tx: ccc.TransactionLike, capacities, lock): ccc.Transaction -orderManager.mint(tx: ccc.TransactionLike, lock, info, amounts): ccc.Transaction -logicManager.deposit(tx: ccc.TransactionLike, qty, amount, lock): ccc.Transaction -``` - -The key difference: managers no longer call `tx.addUdtHandlers()` or `tx.addHeaders()`. Instead: -- CellDeps are added via `tx.addCellDeps()` (already exists on `ccc.Transaction`) -- UDT completion is handled by the caller at transaction completion time -- Headers are fetched via inlined CCC client calls; `getHeader()`/`HeaderKey` removed entirely - -## Architectural Patterns - -### Pattern 1: Manager + Utility Functions (replacing Manager + SmartTransaction) - -**What:** Stateless manager classes with methods that operate on plain `ccc.Transaction`. Side concerns (UDT balancing, fee completion) handled by caller using CCC-native methods. - -**When to use:** All domain operations that modify transactions. - -**Trade-offs:** -- Pro: Managers are simpler, no coupling to custom transaction subclass -- Pro: Callers can use any completion strategy (CCC's completeFeeBy, completeFeeChangeToOutput, etc.) -- Con: Caller must remember to call UDT completion and fee completion separately -- Con: Slightly more boilerplate at call sites - -**Example:** -```typescript -// Application code (e.g., bot) -const tx = ccc.Transaction.default(); - -// Domain operations -orderManager.addMatch(tx, bestMatch); - -// UDT completion (new pattern using CCC Udt) -const completedTx = await ickbUdt.completeBy(tx, signer); - -// Fee completion (CCC native) -await completedTx.completeFeeBy(signer); - -// Send -await signer.sendTransaction(completedTx); -``` - -### Pattern 2: IckbUdt Subclass with Overridden Balance Calculation - -**What:** `IckbUdt extends udt.Udt` overriding `infoFrom()` to account for the triple-representation value model. - -**When to use:** Whenever iCKB UDT balancing is needed (order creation, deposit completion, any tx involving iCKB tokens). - -**Trade-offs:** -- Pro: All CCC Udt methods (completeBy, completeInputsByBalance, getBalanceBurned) automatically work with iCKB's special value model -- Pro: Consistent with CCC ecosystem patterns -- other projects can adopt the same pattern -- Con: Requires header fetching inside infoFrom(), which adds async complexity -- Con: `IckbUdt` needs references to `logicScript` and `daoManager` for cell type detection - -**Example:** See the `IckbUdt` code example in the "CCC Udt Adoption for iCKB" section above. - -### Pattern 3: Explicit Transaction Completion Pipeline - -**What:** Instead of SmartTransaction's "magic" `completeFee()` that internally handles UDT balancing, make the completion pipeline explicit at the call site. - -**When to use:** All application-level transaction building. - -**Trade-offs:** -- Pro: Transparent -- every step is visible -- Pro: Composable -- easy to add/remove steps -- Pro: No hidden state (no udtHandlers map, no headers map) -- Con: Every call site must follow the same pattern (consider a helper function) - -**Example:** -```typescript -// Helper function to standardize the completion pipeline -export async function completeIckbTransaction( - tx: ccc.Transaction, - signer: ccc.Signer, - ickbUdt: IckbUdt, -): Promise { - // Step 1: Complete iCKB UDT inputs and change - const completedTx = await ickbUdt.completeBy(tx, signer); - - // Step 2: Complete CKB fee (with DAO profit awareness if needed) - await completedTx.completeFeeBy(signer); - - return completedTx; -} -``` - -## Anti-Patterns - -### Anti-Pattern 1: Extending ccc.Transaction with Custom Subclass - -**What people do:** Create `SmartTransaction extends ccc.Transaction` to add domain-specific state. - -**Why it's wrong:** -- CCC's methods (`completeFee`, `completeInputsByCapacity`) return `ccc.Transaction`, not the subclass -- leading to type coercion issues -- The subclass couples UDT concerns (balancing) with transaction concerns (inputs/outputs) into one God object -- CCC's `Udt` class already provides the UDT completion features that SmartTransaction implemented -- The ecosystem rejected this pattern (no adoption) -- Makes it impossible to use CCC's newer completion methods directly - -**Do this instead:** Use plain `ccc.Transaction` and compose domain operations through utility functions and CCC's `Udt` class. - -### Anti-Pattern 2: Storing Headers in the Transaction Object - -**What people do:** Keep a `headers: Map` on SmartTransaction for lookups during balance calculation. - -**Why it's wrong:** -- CCC's Client Cache already caches headers fetched via the client -- The headers map creates shared mutable state between cloned transactions -- Header dependencies (`headerDeps`) are already tracked by `ccc.Transaction` - -**Do this instead:** Use `client.getTransactionWithHeader()` or `client.getHeaderByNumber()` and rely on CCC's client-side caching. For transaction-specific header operations (like DAO profit calculation), pass headers explicitly. - -### Anti-Pattern 3: Generic UdtHandler Interface in Utils - -**What people do:** Define a `UdtHandler` interface in `@ickb/utils` that all UDT types implement. - -**Why it's wrong:** -- CCC's `Udt` class already provides this abstraction with a richer API -- The custom `UdtHandler` interface creates a parallel type system that doesn't interop with CCC ecosystem tools -- Forces `SmartTransaction` dependency (methods take `SmartTransaction` parameter) - -**Do this instead:** Use CCC's `Udt` class directly. For iCKB-specific behavior, subclass `Udt`. - -## Build Order - -> **Note:** This research originally suggested a per-package bottom-up build order. The actual ROADMAP uses a **feature-slice approach** instead — each removal is chased across ALL packages so the build stays green at every step. See `.planning/ROADMAP.md` for the authoritative 7-phase structure (SmartTransaction Removal → CCC Utility Adoption → Udt Investigation → Deprecated API Replacement → Core UDT Refactor → SDK Completion → Full Verification). App migration is deferred to a future milestone. - -The dependency graph still applies to the order of operations within each feature-slice: - -``` -@ickb/utils (foundation -- SmartTransaction, CapacityManager, getHeader live here) - | - +---> @ickb/dao (depends on utils) - +---> @ickb/order (depends on utils) - | | - +---> @ickb/core (depends on dao + utils) - | - @ickb/sdk (depends on all above) -``` - -**Rationale for dependency order within feature-slices:** - -1. **@ickb/utils first** because every other package imports it. Changes to exports here affect all downstream packages. - -2. **@ickb/dao and @ickb/order in parallel** since neither depends on the other directly. - -3. **@ickb/core after dao** because `@ickb/core` depends on `@ickb/dao` (LogicManager has a DaoManager). - -4. **@ickb/sdk last** because it depends on all domain packages. - -**Critical dependency:** The `IckbUdt` subclass design (ROADMAP Phase 3 investigation) is the riskiest and most uncertain part. If CCC's `Udt` class cannot be subclassed effectively for the triple-representation model, the architecture may need to fall back to a wrapper pattern rather than inheritance. - -## Integration Points - -### External Services - -| Service | Integration Pattern | Notes | -|---------|---------------------|-------| -| CKB RPC (via CCC Client) | `ccc.ClientPublicTestnet` / `ccc.ClientPublicMainnet` | All chain queries, cell discovery, transaction submission | -| CCC Client Cache | Transparent caching of headers, cells | Replaces SmartTransaction's `headers` map | -| JoyId Wallet (interface app) | CCC Signer abstraction | No direct API calls, uses CCC's wallet connector pattern | - -### Internal Boundaries - -| Boundary | Communication | Notes | -|----------|---------------|-------| -| Utils <-> Domain | Domain managers call utility functions (collect, unique, binarySearch, codec) | Direction: domain calls utils, never reverse. CapacityManager removed; CCC's `completeInputsByCapacity()` replaces it | -| Domain <-> SDK | SDK instantiates and orchestrates domain managers | SDK owns manager lifecycle via `getConfig()` | -| SDK <-> Apps | Apps call SDK methods, receive immutable snapshots | `SystemState` is a plain readonly object, no circular dependency | -| Domain <-> CCC Udt | `IckbUdt extends udt.Udt` in `@ickb/core` | CCC Udt is the extension point; iCKB does NOT modify CCC code | -| All packages <-> CCC | Import `{ ccc } from "@ckb-ccc/core"` | One-way dependency: iCKB depends on CCC, never reverse. PRs go upstream | - -## Scaling Considerations - -| Scale | Architecture Adjustments | -|-------|--------------------------| -| Current (few users, single bot) | Monolith is fine. Single process bot, single RPC endpoint | -| Multiple bots | Bot lock script array in SDK already supports this. No architecture change needed | -| High-frequency order matching | OrderManager.bestMatch() is O(n^2) over order pool. If order count grows beyond ~1000, consider pre-indexing by ratio range | -| Multiple UDT types | CCC's Udt class is per-token instance. Each additional token requires a new Udt instance with its own script. The IckbUdt subclass is specific to iCKB -- other tokens use base Udt | - -## Sources - -- CCC `@ckb-ccc/udt` source code: `/workspaces/stack/forks/ccc/packages/udt/src/udt/index.ts` (HIGH confidence -- direct code examination) -- CCC `@ckb-ccc/core` Transaction class: `/workspaces/stack/forks/ccc/packages/core/src/ckb/transaction.ts` (HIGH confidence -- direct code examination) -- Current SmartTransaction: `/workspaces/stack/packages/utils/src/transaction.ts` (HIGH confidence -- direct code examination) -- Current IckbUdtManager: `/workspaces/stack/packages/core/src/udt.ts` (HIGH confidence -- direct code examination) -- Current UdtManager/UdtHandler: `/workspaces/stack/packages/utils/src/udt.ts` (HIGH confidence -- direct code examination) -- PROJECT.md decisions and context (HIGH confidence -- project documentation) -- Current codebase architecture analysis: `.planning/codebase/ARCHITECTURE.md` (HIGH confidence) - ---- -*Architecture research for: iCKB library suite CCC refactoring* -*Researched: 2026-02-21* diff --git a/.planning/research/FEATURES.md b/.planning/research/FEATURES.md deleted file mode 100644 index 383a871..0000000 --- a/.planning/research/FEATURES.md +++ /dev/null @@ -1,223 +0,0 @@ -# Feature Research - -**Domain:** CCC-based CKB protocol library suite (NervosDAO liquidity / iCKB) -**Researched:** 2026-02-21 -**Confidence:** HIGH (based on codebase analysis, CCC docs, existing protocol architecture, npm ecosystem survey) - -## Feature Landscape - -### Table Stakes (Users Expect These) - -Features that library consumers (app developers, frontends, the bot) expect to exist. Missing any of these means the library suite is not production-ready for npm publication. - -| Feature | Why Expected | Complexity | Notes | -|---------|--------------|------------|-------| -| **TS-1: SmartTransaction removal** | SmartTransaction extends `ccc.Transaction` with abandoned ecosystem semantics; consumers expect to work with plain `ccc.Transaction` | HIGH | Core refactor touching all 5 packages and all managers. Replace with utility functions that operate on `ccc.Transaction` directly. UDT handler map and header cache must be externalized or passed as parameters. | -| **TS-2: CCC utility deduplication** | Library consumers expect no redundant code when CCC already provides equivalents | LOW | Adopt `ccc.numMax`/`ccc.numMin` for `max`/`min`, CCC's `gcd()`, `isHex()`, `hexFrom()`. Keep iCKB-unique utilities (`binarySearch`, `shuffle`, `unique`, `collect`, `BufferedGenerator`, `MinHeap`). | -| **TS-3: Clean public API surface** | npm packages must export only intentional public API, not internal implementation details | MEDIUM | Audit all `export *` barrel files. Mark internal symbols with `@internal` or move to non-exported files. Ensure each package's entry point (`index.ts`) is curated. | -| **TS-4: Complete Lumos removal** | Consumers expect zero `@ckb-lumos/*` dependencies in the published library packages | MEDIUM | Library packages (`packages/*`) already use CCC. Lumos remains only in legacy apps (`bot`, `interface`, `tester`). App migration is the gate. Legacy packages `@ickb/lumos-utils` and `@ickb/v1-core` should not be dependencies of any new package. | -| **TS-5: Bot app migration to CCC** | Bot is the primary protocol operator; it must use the new library packages to validate they work end-to-end | HIGH | 897-line file using `@ickb/v1-core` + `@ckb-lumos/*`. Needs full rewrite to use `@ickb/sdk` + `@ickb/core` + CCC signers. Validates the entire library stack under real production load. | -| **TS-6: Interface app migration to CCC** | The user-facing DApp must use the new packages; shipping two implementations is unsustainable | MEDIUM | Straight migration (same UI). Swap `@ickb/v1-core` + `@ckb-lumos/*` for `@ickb/sdk` + CCC. React + TanStack Query architecture stays. ~1,158 lines across 8 files. Already uses CCC for wallet connection. | -| **TS-7: Tester app migration to CCC** | Tester validates protocol behavior; must exercise the new packages | MEDIUM | 469-line simulation file. Similar migration pattern to bot. | -| **TS-8: Correct NervosDAO operation semantics** | Deposit, withdrawal request, and withdrawal must work correctly with all DAO constraints (64-output limit, epoch-based since, header deps) | Already done | Already implemented in `DaoManager`. Validated by existing faucet/sampler apps. Maintain and verify during SmartTransaction removal. | -| **TS-9: iCKB conservation law enforcement** | `Input UDT + Input Receipts = Output UDT + Input Deposits` must be maintained in all transaction construction | Already done | Enforced by on-chain contract. Library must construct transactions that satisfy this invariant. `IckbUdtManager.getInputsUdtBalance` already accounts for all three representations. | -| **TS-10: Multi-network support (mainnet/testnet)** | Protocol is deployed on both networks; library must support both via `IckbSdk.from("mainnet" | "testnet")` | Already done | Already implemented in `constants.ts` with per-network dep groups and bot scripts. Devnet support via custom config objects. | -| **TS-11: npm publication with provenance** | CKB ecosystem expects packages on npm with `access: public` and `provenance: true` for supply chain verification | LOW | Already configured. Changeset-based versioning (`1001.0.0`). Ensure `package.json` files have correct `exports`, `types`, `main` fields pointing to built output. | -| **TS-12: Proper TypeScript type exports** | Library consumers expect full type information, strict mode compatibility, and no `any` leaks in public API | MEDIUM | Strict mode already enforced (`noUncheckedIndexedAccess`, `verbatimModuleSyntax`, `noImplicitOverride`). Audit public-facing types for completeness. Ensure `.d.ts` files are generated and referenced. | - -### Differentiators (Competitive Advantage) - -Features that set the iCKB library suite apart from other CKB protocol libraries (Lumos, CKB SDK JS, RGB++ SDK, NervDAO). Not required for launch, but make the library significantly more valuable. - -| Feature | Value Proposition | Complexity | Notes | -|---------|-------------------|------------|-------| -| **D-1: Multi-representation UDT value tracking** | iCKB value exists as xUDT tokens + receipt cells + DAO deposit cells simultaneously. No other CKB library handles this. The `IckbUdtManager` already computes unified balance across all three forms. | Already done (needs refinement) | Current implementation lives inside `SmartTransaction` override. After SmartTransaction removal, this logic must be preserved as standalone functions or a CCC `Udt`-compatible interface. Key differentiator: a UDT whose balance cannot be determined by reading cell data alone -- requires header lookups and receipt decoding. | -| **D-2: CCC Udt subclassing investigation** | If CCC's `Udt` class (via SSRI) can be extended for iCKB's multi-representation value, it would make iCKB a first-class citizen in the CCC ecosystem. Other protocol tokens could follow the pattern. | HIGH | CCC's `@ckb-ccc/udt` package uses SSRI server for UDT operations. iCKB's exchange rate is deterministic from block headers, not from an SSRI server. Subclassing may not be the right approach -- a compatible interface or wrapper may be better. Requires investigation of CCC's `Udt` API surface. | -| **D-3: Conversion preview with maturity estimation** | `IckbSdk.estimate()` provides real-time conversion preview with fee calculation AND estimated order fulfillment time based on pool liquidity analysis. No other CKB DEX SDK provides maturity estimation. | Already done | `IckbSdk.estimate()` and `IckbSdk.maturity()` already implement this. Ensure these survive SmartTransaction removal. | -| **D-4: Pool snapshot-based liquidity analysis** | Bot cells carry deposit pool snapshots (compact binary encoding) that enable fast liquidity estimation without scanning all deposit cells. | Already done | `PoolSnapshot` codec in `sdk/src/codec.ts`. Bot writes snapshots; SDK reads them. Unique protocol feature. | -| **D-5: Async generator cell discovery pattern** | Lazy evaluation via `async *findDeposits()`, `async *findOrders()` etc. with configurable batch sizes. More memory-efficient than collecting all cells upfront. | Already done | Pattern used consistently across `DaoManager`, `LogicManager`, `OrderManager`, `UdtManager`, `CapacityManager`. This is a genuine DX advantage over Lumos's eager collection pattern. | -| **D-6: Composable manager pattern with ScriptDeps** | Uniform `{ script, cellDeps }` interface enables managers to compose into transactions without knowing about each other. Clean dependency injection. | Already done | `DaoManager`, `OrderManager`, `LogicManager`, `OwnedOwnerManager`, `CapacityManager` all implement `ScriptDeps`. Pattern enables devnet testing with custom configs. | -| **D-7: Exchange rate calculation from block headers** | Deterministic CKB-to-iCKB conversion without oracles. `ickbExchangeRatio()` derives the rate from `header.dao.ar` (accumulated rate). | Already done | `convert()` and `ickbExchangeRatio()` in `packages/core/src/udt.ts`. Unique to iCKB protocol. Includes soft cap penalty calculation. | -| **D-8: Limit order lifecycle management** | Full mint/match/melt lifecycle for on-chain limit orders. `OrderManager` handles order creation, partial fills (preserving value conservation), and cancellation. | Already done | 988-line `OrderManager`. Includes ratio comparison, concavity checks, DOS prevention via `ckb_min_match_log`. Differentiated from CKB DEX SDK by being specifically designed for iCKB/CKB pair with integrated exchange ratio. | -| **D-9: Upstream CCC contribution pipeline** | Project has a track record of 12 merged CCC PRs. Patterns developed here become CCC-native features. This is a moat -- the maintainer shapes the framework the library depends on. | Ongoing | Continue identifying reusable patterns (FeePayer PR #328, potential UDT extensions). Each upstream merge reduces local code and increases ecosystem value. | -| **D-10: Owned-owner withdrawal delegation** | Solves NervosDAO's lock-size constraint for withdrawal delegation. `OwnedOwnerManager` handles the 1:1 pairing of owned (withdrawal request) and owner (authorization) cells via relative offset. | Already done | Unique to iCKB protocol. No other NervosDAO integration handles delegated withdrawals. | - -### Anti-Features (Commonly Requested, Often Problematic) - -Features that seem good but create problems in this context. Explicitly document what NOT to build. - -| Feature | Why Requested | Why Problematic | Alternative | -|---------|---------------|-----------------|-------------| -| **AF-1: SmartTransaction as ecosystem standard** | Was proposed as a universal CKB transaction builder pattern | Abandoned by CCC maintainers and broader ecosystem. No adoption outside iCKB. Subclassing `ccc.Transaction` couples to CCC internals. | Use utility functions on plain `ccc.Transaction`. UDT handler logic becomes standalone. If CCC PR #328 (FeePayer) lands, adopt that for fee completion. | -| **AF-2: Custom Molecule codec library** | Tempting to build a richer codec layer than CCC's `mol.*` | CCC already provides `mol.union`, `ccc.Entity.Base`, `@ccc.codec`. Custom codecs duplicate effort and diverge from ecosystem. | Use CCC's Molecule codecs exclusively. Already migrated from custom `mol.*` APIs. | -| **AF-3: UI/UX redesign during migration** | Interface app migration feels like a chance to modernize the UI | Conflates two concerns. UI redesign delays migration. The goal is to swap internals, not redesign the product. | Straight migration only: same components, same React Query patterns, swap Lumos for CCC+SDK. UI redesign is a separate future effort (out of scope). | -| **AF-4: Custom blockchain indexer** | Some CKB projects build custom indexers for better query performance | CCC's `findCells`/`findCellsOnChain` with built-in caching covers all current needs. Custom indexer adds massive operational complexity for marginal gain at iCKB's scale. | Use CCC's client cell queries with the existing filter patterns. The async generator pattern already provides efficient lazy evaluation. | -| **AF-5: Multi-chain / L2 token bridging** | RGB++ protocol enables cross-chain iCKB. Tempting to add bridging to the library. | Bridging requires fundamentally different architecture (BTC time locks, RGB++ lock scripts, different transaction patterns). Premature integration creates coupling. | Keep library focused on L1. Bridging is a separate concern that can compose with these packages. If RGB++ bridge is needed later, it should be a separate package. | -| **AF-6: Embedded wallet/signer management** | Some SDKs bundle wallet management (key storage, mnemonic handling) | CCC already provides comprehensive signer abstraction (`ccc.Signer`, `ccc.SignerCkbPrivateKey`, JoyId integration). Duplicating this creates security liability. | Delegate all signing to CCC's signer infrastructure. The SDK accepts `ccc.Signer` or `ccc.Script` -- it never manages keys. | -| **AF-7: Database/state persistence layer** | Bot and interface could benefit from persistent state (order history, balance cache) | All state is on-chain. Adding a database creates consistency problems (stale state vs chain state). The current stateless design is a feature, not a limitation. | Continue reading all state from L1 via CCC client. Pool snapshots (D-4) provide efficient state approximation without a database. | -| **AF-8: New reference/example apps** | More apps might help adoption | Existing 5 apps (bot, interface, faucet, sampler, tester) already demonstrate all library capabilities. Adding more dilutes maintenance focus. | Polish existing apps. They serve as living documentation. | -| **AF-9: CCC framework fork** | Tempting to fork CCC to get features faster | Forking creates maintenance burden and diverges from ecosystem. Upstream PRs are the correct approach. | Submit PRs upstream (already doing this with 12 merged). Track CCC PR #328 (FeePayer). Use `forks/ccc/` local build for testing changes before they land upstream. | -| **AF-10: On-chain contract changes** | Protocol improvements seem natural alongside library work | All contracts are deployed with zero-args locks (immutable, non-upgradable). Even if desirable, contract changes are impossible. | Library must match existing on-chain contract behavior exactly. All protocol rules are fixed. | - -## Feature Dependencies - -``` -SmartTransaction Removal (TS-1) - | - +-- enables --> CCC Utility Deduplication (TS-2) - | (deduplicate utilities after core restructuring) - | - +-- enables --> Clean Public API (TS-3) - | (can't finalize API until SmartTransaction is gone) - | - +-- enables --> Bot Migration (TS-5) - | (bot should migrate to final API, not intermediate) - | - +-- enables --> Interface Migration (TS-6) - | (same reasoning) - | - +-- enables --> Tester Migration (TS-7) - | (same reasoning) - | - +-- preserves --> Multi-representation UDT (D-1) - | (UDT balance logic must survive removal) - | - +-- preserves --> Conversion Preview (D-3) - | (estimation logic must survive removal) - -CCC Udt Investigation (D-2) - | - +-- can parallel --> SmartTransaction Removal (TS-1) - | (design investigation, no code changes -- can proceed in parallel) - | - +-- informs --> Multi-representation UDT (D-1) - (whether to use Udt interface or custom) - -Bot Migration (TS-5) - | - +-- requires --> SmartTransaction Removal (TS-1) - +-- requires --> Clean Public API (TS-3) - +-- validates --> All library packages - -Interface Migration (TS-6) - | - +-- requires --> SmartTransaction Removal (TS-1) - +-- requires --> Clean Public API (TS-3) - -Lumos Removal (TS-4) - | - +-- requires --> Bot Migration (TS-5) - +-- requires --> Interface Migration (TS-6) - +-- requires --> Tester Migration (TS-7) - -npm Publication (TS-11) - | - +-- requires --> Clean Public API (TS-3) - +-- requires --> Type Exports (TS-12) - +-- requires --> SmartTransaction Removal (TS-1) -``` - -### Dependency Notes - -- **TS-1 (SmartTransaction Removal) is the critical path.** Every downstream task depends on it. It must happen first and must preserve D-1 (multi-representation UDT) and D-3 (conversion preview) functionality. -- **TS-5 (Bot Migration) validates the entire stack.** The bot exercises deposits, withdrawals, order matching, fee completion, and UDT balancing under real conditions. It is the integration test for the library suite. -- **TS-4 (Lumos Removal) is the final gate.** It can only happen after all three legacy apps are migrated. It removes `@ickb/lumos-utils`, `@ickb/v1-core`, and all `@ckb-lumos/*` from the monorepo. -- **D-2 (CCC Udt Investigation) is exploratory.** It can proceed in parallel with SmartTransaction removal (design investigation, not code changes). Findings inform the API design of D-1 but the library can ship with a custom `UdtHandler` interface regardless. -- **CCC PR #328 (FeePayer) is external.** Track it but do not depend on it. Design the SmartTransaction replacement so that FeePayer can be adopted later if it merges. - -## MVP Definition - -### Launch With (v1) - -Minimum viable state for npm publication of clean CCC-aligned library packages. - -- [ ] **TS-1: SmartTransaction removal** -- Replace with utility functions on `ccc.Transaction`. This is the single most important task. All manager methods must accept `ccc.TransactionLike` instead of `SmartTransaction` (CCC convention: TransactionLike input, Transaction output). -- [ ] **TS-2: CCC utility deduplication** -- Adopt CCC equivalents for `max`/`min`/`gcd`/`isHex`/`hexFrom`. -- [ ] **TS-3: Clean public API** -- Audit exports, ensure intentional public surface, proper type exports. -- [ ] **TS-5: Bot migration** -- Validates the library packages work end-to-end under production conditions. -- [ ] **D-1: Multi-representation UDT preservation** -- Ensure `IckbUdtManager` functionality survives SmartTransaction removal. -- [ ] **TS-11: npm publication** -- Publish updated packages with clean API and provenance. - -### Add After Validation (v1.x) - -Features to add once core library packages are stable and published. - -- [ ] **TS-6: Interface migration** -- Trigger: bot migration succeeds, proving the API works. -- [ ] **TS-7: Tester migration** -- Trigger: bot migration succeeds. -- [ ] **TS-4: Lumos removal** -- Trigger: all three legacy apps migrated. -- [ ] **D-2: CCC Udt investigation** -- Trigger: SmartTransaction removal complete, CCC UDT API stabilizes. -- [ ] **TS-12: Type export audit** -- Trigger: public API finalized. - -### Future Consideration (v2+) - -Features to defer until library suite is stable and adopted. - -- [ ] **D-9: Upstream CCC contributions** -- Continue identifying reusable patterns. Track FeePayer PR #328. -- [ ] **Pool snapshot optimization** -- Improve compact encoding or move to a more structured format if bot requirements grow. -- [ ] **Additional UDT support** -- If other xUDT tokens need similar multi-representation handling, generalize the pattern. - -## Feature Prioritization Matrix - -| Feature | User Value | Implementation Cost | Priority | -|---------|------------|---------------------|----------| -| TS-1: SmartTransaction removal | HIGH | HIGH | **P1** | -| TS-2: CCC utility deduplication | MEDIUM | LOW | **P1** | -| TS-3: Clean public API | HIGH | MEDIUM | **P1** | -| TS-5: Bot migration | HIGH | HIGH | **P1** | -| D-1: Multi-representation UDT | HIGH | MEDIUM | **P1** | -| TS-11: npm publication | HIGH | LOW | **P1** | -| TS-6: Interface migration | HIGH | MEDIUM | **P2** | -| TS-7: Tester migration | MEDIUM | MEDIUM | **P2** | -| TS-4: Lumos removal | MEDIUM | LOW | **P2** | -| TS-12: Type export audit | MEDIUM | LOW | **P2** | -| D-2: CCC Udt investigation | MEDIUM | HIGH | **P2** | -| D-3: Conversion preview | HIGH | Already done | **--** | -| D-4: Pool snapshot | HIGH | Already done | **--** | -| D-5: Async generators | HIGH | Already done | **--** | -| D-6: ScriptDeps pattern | HIGH | Already done | **--** | -| D-7: Exchange rate | HIGH | Already done | **--** | -| D-8: Order lifecycle | HIGH | Already done | **--** | -| D-9: Upstream contributions | MEDIUM | Ongoing | **P3** | -| D-10: Owned-owner delegation | HIGH | Already done | **--** | - -**Priority key:** -- P1: Must have -- blocks npm publication of clean CCC-aligned packages -- P2: Should have -- add after P1 validates the library stack -- P3: Nice to have -- ongoing improvement - -## Competitor Feature Analysis - -| Feature | NervDAO (CCC) | Lumos NervosDAO | CKB DEX SDK | iCKB Library Suite | -|---------|---------------|-----------------|-------------|-------------------| -| NervosDAO deposit/withdraw | Yes (UI only) | Yes (framework) | No | Yes (library + apps) | -| Liquid staking token | No | No | No | Yes (iCKB xUDT) | -| Multi-representation value | No | No | No | Yes (xUDT + receipts + deposits) | -| Limit order matching | No | No | Yes (generic) | Yes (iCKB-specific, integrated rate) | -| Exchange rate calculation | No | No | No | Yes (deterministic from headers) | -| Pool liquidity analysis | No | No | No | Yes (pool snapshots) | -| Maturity estimation | No | No | No | Yes (order fulfillment time) | -| CCC-native (no Lumos) | Yes | No (IS Lumos) | Partial | Yes (target state) | -| npm published | No (app only) | Yes | Yes | Yes (5 packages) | -| Delegated DAO withdrawals | No | No | No | Yes (owned-owner pattern) | -| Wallet abstraction | Yes (multi-wallet) | Yes (secp256k1) | Yes (multiple locks) | Yes (via CCC signers) | -| TypeScript strict mode | Unknown | No | Unknown | Yes (strictest settings) | - -**Analysis:** The iCKB library suite has no direct competitor. NervDAO is a UI application, not a library. Lumos is a general framework being superseded by CCC. CKB DEX SDK handles generic order matching but not protocol-specific logic. The iCKB suite is the only npm-published library that provides NervosDAO liquid staking with multi-representation UDT handling, integrated exchange rates, and limit order matching -- all built on the modern CCC framework. - -## Sources - -- Codebase analysis: `packages/*/src/*.ts` (direct reading) -- HIGH confidence -- CCC GitHub repository: [ckb-devrel/ccc](https://github.com/ckb-devrel/ccc) -- HIGH confidence -- CCC documentation: [docs.ckbccc.com](https://docs.ckbccc.com/) -- HIGH confidence -- CCC UDT package: [ckb-devrel/ccc/packages/udt](https://github.com/ckb-devrel/ccc/tree/master/packages/udt) -- MEDIUM confidence (limited docs) -- CCC FeePayer PR: [ckb-devrel/ccc/pull/328](https://github.com/ckb-devrel/ccc/pull/328) -- MEDIUM confidence (open PR, subject to change) -- NervDAO: [ckb-devrel/nervdao](https://github.com/ckb-devrel/nervdao) -- MEDIUM confidence -- @ickb/utils on npm: [npmjs.com/@ickb/utils](https://www.npmjs.com/package/@ickb/utils/v/1000.0.42?activeTab=versions) -- HIGH confidence -- iCKB protocol overview: [nervos.org/knowledge-base/Unlocking_CKB_Liquidity_iCKB](https://www.nervos.org/knowledge-base/Unlocking_CKB_Liquidity_iCKB) -- HIGH confidence -- Nervos CKB docs: [docs.nervos.org](https://docs.nervos.org/) -- HIGH confidence -- CKB DEX SDK: [nervina-labs/ckb-dex-sdk](https://github.com/nervina-labs/ckb-dex-sdk) -- MEDIUM confidence -- Enhanced UDT Standard discussion: [Nervos Talk](https://talk.nervos.org/t/enhanced-udt-standard/8354) -- LOW confidence (discussion, not specification) - ---- -*Feature research for: CCC-based iCKB protocol library suite* -*Researched: 2026-02-21* diff --git a/.planning/research/PITFALLS.md b/.planning/research/PITFALLS.md deleted file mode 100644 index c8be292..0000000 --- a/.planning/research/PITFALLS.md +++ /dev/null @@ -1,287 +0,0 @@ -# Pitfalls Research - -**Domain:** CKB/CCC library migration -- removing SmartTransaction, adopting CCC UDT, migrating apps from Lumos -**Researched:** 2026-02-21 -**Confidence:** HIGH (derived from direct codebase analysis, CCC source inspection, and domain-specific contract constraints) - -## Critical Pitfalls - -### Pitfall 1: Removing SmartTransaction Before Extracting All Implicit Behaviors - -**What goes wrong:** -SmartTransaction is not just a thin wrapper around `ccc.Transaction`. It carries three orthogonal responsibilities that are interleaved throughout 9 files (55 references): (1) UDT handler registration and dispatch, (2) header caching with multi-key lookup, and (3) DAO-aware `getInputsCapacity` and `completeFee` overrides including the 64-output NervosDAO check. Developers see "remove SmartTransaction, use `ccc.Transaction` + utility functions" and attempt a mechanical find-and-replace, missing that `completeFee` silently iterates all registered UDT handlers before calling `super.completeFee()`, that `clone()` shares `udtHandlers` and `headers` maps across transaction copies (shared-state semantics), and that `getInputsCapacity` adds DAO withdrawal profit to the capacity total. A naive replacement that only extracts the obvious methods will produce transactions that fail on-chain because (a) UDT change cells are never added, (b) DAO withdrawal profits are not counted in capacity balancing, or (c) headers needed for withdrawal are not in `headerDeps`. - -**Why it happens:** -SmartTransaction's design buries critical side effects in method overrides that are not visible from call sites. The callers (e.g., `LogicManager.deposit`, `DaoManager.requestWithdrawal`, `OrderManager.mint`) call `tx.addUdtHandlers()`, `tx.addHeaders()`, and `tx.getHeader()` -- methods that only exist on SmartTransaction, not on `ccc.Transaction`. These are the implicit contract. But the highest-stakes behavior -- `completeFee` iterating all handlers and `getInputsCapacity` adding DAO profit -- is triggered by the signer at transaction submission time, far from where handlers/headers were registered. - -**How to avoid:** -1. Before removing anything, catalog every SmartTransaction-specific method used across the codebase. The complete list: `addUdtHandlers`, `addHeaders`, `getHeader`, `hasUdtHandler`, `getUdtHandler`, `encodeUdtKey`, `encodeHeaderKey`, `completeFee` (override), `getInputsCapacity` (override), `getInputsUdtBalance` (override), `getOutputsUdtBalance` (override), `clone` (override with shared maps), `copy` (override with map merging), `default` (override), `from` (override). -2. Design the replacement as standalone functions for the UDT completion concern (`completeUdtChange(tx, signer)`). Note: `getInputsCapacity` DAO profit accounting does NOT need a utility — CCC's `Transaction.getInputsCapacity()` handles this natively via `getInputsCapacityExtra()` → `Cell.getDaoProfit()`. Header management: `getHeader()` and `HeaderKey` are removed entirely; call sites inline CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`); `addHeaders()` call sites push to `tx.headerDeps` directly. Validate that each original override has a corresponding replacement (inlined CCC call or CCC-native method). -3. Write characterization tests BEFORE refactoring: for a known set of inputs, capture the exact `completeFee` output (number of added inputs, whether change was added) and the exact `getInputsCapacity` return value. Run these tests against the new utility functions. - -**Warning signs:** -- Any `completeFee` call that returns `[0, false]` when it previously returned `[N, true]` -- means UDT change is missing -- Transactions rejected on-chain with "ImbalancedCapacity" -- means DAO profit is not being counted -- "Header not found in HeaderDeps" errors -- means header caching was lost -- Off-by-one in output count near the 64-output NervosDAO limit -- means the DAO check was lost from `completeFee` - -**Phase to address:** -Phase 1 (Library refactor). This must be the first step -- all five library packages and all downstream apps depend on SmartTransaction. Getting this wrong blocks everything else. - ---- - -### Pitfall 2: Conservation Law Violation When Subclassing CCC Udt for iCKB Multi-Representation Value - -**What goes wrong:** -iCKB value exists in three on-chain forms: xUDT tokens (standard `u128 LE` balance), receipt cells (representing pending deposit conversions, carrying `{depositQuantity, depositAmount}`), and DAO deposit cells (locked CKB). The iCKB Logic contract enforces a conservation law: `input_udt + input_receipts = output_udt + input_deposits`. CCC's `Udt` class only understands form (1) -- it counts `u128 LE` balances in cells with a matching type script. If you subclass `Udt` and override `infoFrom`/`balanceFrom` to also count receipts and deposits (as `IckbUdtManager` currently does), you create a class that claims a balance that CCC's generic transaction completion logic does not understand. When CCC's `Udt.completeInputsByBalance` adds inputs to satisfy the declared balance, it may add receipt or deposit cells that trigger the conservation law in unexpected ways, or it may fail to add the correct header deps needed for receipt/deposit value calculation. - -Concretely, `IckbUdtManager.getInputsUdtBalance` currently (a) counts xUDT balances, (b) converts receipt cells to iCKB value using the block header's accumulated rate, and (c) subtracts deposit value when a deposit-to-withdrawal-request conversion is happening. This logic requires `tx.getHeader()` -- a SmartTransaction method -- and depends on knowing the transaction's intent (is a deposit being converted to a withdrawal request?). CCC's `Udt` has no concept of header-dependent balance calculation or intent-aware accounting. - -**Why it happens:** -The temptation is to make `IckbUdt extends Udt` so that CCC's generic transaction completion (`completeBy`, `completeInputsByBalance`) "just works" for iCKB. But iCKB's multi-representation value model is fundamentally incompatible with the assumption that UDT balance = sum of `u128 LE` fields in matching type cells. The CCC `Udt` class was designed for standard xUDT tokens, not for protocol-specific tokens with conservation laws spanning multiple cell types. - -**How to avoid:** -1. The preferred approach (confirmed in Phase 3 research) is to subclass `Udt` as `IckbUdt`, overriding `infoFrom()`. Input cells have `outPoint` set (resolved via `CellInput.getCell()`), enabling header fetches for receipt/deposit value calculation. `CellAny` has `capacityFree` for deposit valuation. See 03-RESEARCH.md for the corrected design. -2. If subclassing proves unviable, the fallback is to keep multi-representation accounting in iCKB-specific standalone functions (refactored from `IckbUdtManager`), using CCC's `Udt` only for standard xUDT operations (cell discovery, basic balance reading). -3. Whichever approach is chosen, ensure that CCC's `Udt.completeInputsByBalance()` does not inadvertently add receipt or deposit cells as if they were standard xUDT inputs. Verify that the conservation law (`input_udt + input_receipts = output_udt + input_deposits`) is enforced correctly by the overridden methods. -4. Always add required `headerDeps` explicitly -- CCC's client cache handles header fetching performance, but `headerDeps` must be on the transaction for on-chain validation. - -**Warning signs:** -- Tests where `udt.calculateBalance(signer)` returns a different value than the on-chain xUDT balance visible in an explorer -- Transaction completion that adds iCKB receipt cells as if they were xUDT cells -- Missing `headerDeps` in completed transactions (receipts require the header of their creation TX) -- CCC's generic `completeInputsByBalance()` selecting cells that trigger the conservation law unexpectedly - -**Phase to address:** -Phase 3 (CCC Udt Integration Investigation). The UDT handling architecture must be settled before core implementation (Phase 5), because the apps currently use `SmartTransaction.completeFee` which delegates to `IckbUdtManager.completeUdt`. Phase 3 is specifically designed to resolve this design question. - ---- - -### Pitfall 3: Exchange Rate Divergence Between TypeScript and Rust Contract - -**What goes wrong:** -The TypeScript exchange rate formula in `packages/core/src/udt.ts` must produce byte-identical results to the Rust `ickb_logic` contract's `deposit_to_ickb()` function. The formula is `iCKB = capacity * AR_0 / AR_m` with a soft cap penalty. Any divergence -- even by 1 shannon due to integer division rounding -- causes the conservation law check to fail on-chain, and the transaction is rejected. This is not caught by type checking, linting, or any compile-time analysis. It can only be caught by cross-validation tests that compare TypeScript output against known Rust contract outputs. - -The specific danger points: -- Integer division direction: Rust uses truncating division. TypeScript `BigInt` also truncates, but the order of operations matters. `(a * b) / c` may produce a different result than `a * (b / c)`. -- The soft cap formula: `amount - (amount - 100000) / 10n` where `100000` is `ICKB_SOFT_CAP_PER_DEPOSIT` in CKB units (100,000 * 10^8). Getting the unit wrong by a factor of 10^8 is catastrophic. -- The `depositCapacityDelta` constant: computed as `(82 CKB * AR_0) / ICKB_DEPOSIT_CAP`. This is a compile-time constant in the TypeScript but must match the Rust contract's treatment of occupied capacity (82 bytes for a DAO deposit cell). - -**Why it happens:** -The contract code is in Rust, the library is in TypeScript, and there are zero cross-validation tests. The developer relies on manual inspection to verify formula equivalence. Any future change to either side (e.g., adopting a CCC upstream utility for the conversion) risks introducing a subtle arithmetic difference. - -**How to avoid:** -1. Create a test fixture file with known input/output pairs derived from the Rust contract: deposit amounts at boundary conditions (1000 CKB, 100000 CKB, 1000000 CKB), various accumulated rates, and the exact expected iCKB amounts. -2. Run these as the first test in CI. If the test breaks, it means the TypeScript formula diverged from the contract. -3. Add a comment in `packages/core/src/udt.ts` at each formula step citing the exact Rust source line it corresponds to. -4. Never replace a hand-written arithmetic formula with a CCC utility without verifying the utility produces identical results for the test fixture. - -**Warning signs:** -- Any change to `ickbValue()`, `convert()`, or `ickbExchangeRatio()` in `packages/core/src/udt.ts` -- Changing the `AR_0`, `depositUsedCapacity`, or `ICKB_DEPOSIT_CAP` constants -- On-chain transaction failures with error code 11 (`AmountMismatch`) from the `ickb_logic` script - -**Phase to address:** -Phase 1 (Library refactor) -- add cross-validation tests before any refactoring touches the exchange rate code. This is a safety net for the entire migration. - ---- - -### Pitfall 4: Breaking the Conservation Law During Lumos-to-CCC App Migration - -**What goes wrong:** -The legacy bot app (`apps/bot/src/index.ts`, ~900 lines) builds iCKB transactions using Lumos primitives (`TransactionSkeleton`, `addCells`, `addCkbChange`, `addIckbUdtChange`, etc.). The new library packages build equivalent transactions using CCC primitives. During migration, the developer must produce transactions with **identical on-chain semantics** -- same cell types in the same positions, same data formats, same header deps, same witness structure. The iCKB contracts enforce position-sensitive rules: for example, the `owned_owner` script requires a 1:1 pairing between owner cells and owned cells at specific relative positions (the `owned_distance: i32` field). The order contract requires the master cell to appear at a specific offset from its order cell. Getting the cell ordering wrong produces transactions that pass TypeScript validation but fail on-chain. - -Specifically dangerous patterns in the bot migration: -- `ickbRequestWithdrawalFrom` in Lumos creates paired cells (owned withdrawal request + owner cell) with specific relative positioning. The new `OwnedOwnerManager.requestWithdrawal` must produce identical relative positions. -- `orderSatisfy`/`orderMint` in Lumos produce order cells with `master_distance` encoded as a relative `i32`. The new `OrderManager.mint` uses `Relative.create(1n)` for the same purpose. The byte encoding must be identical. -- The bot's `addCkbChange` + `addIckbUdtChange` sequence in Lumos has specific ordering semantics (iCKB change first, then CKB change). The new `SmartTransaction.completeFee` iterates UDT handlers before calling `super.completeFee()`, preserving this order. But if the replacement utility functions change this order, fee calculation will differ. - -**Why it happens:** -The migration is a "rewrite-in-place" of ~900 lines of Lumos-based transaction building. The developer focuses on making the TypeScript type-check with the new API, but the on-chain contracts don't care about TypeScript types -- they care about byte-level cell layout. The implicit contract between the off-chain code and the on-chain scripts is not captured in any type system. - -**How to avoid:** -1. Migrate the bot in a feature branch and test against CKB testnet before mainnet. -2. For each transaction type the bot produces (deposit, withdrawal request, withdrawal, order match, order melt), capture a "golden" transaction from the Lumos version (serialized bytes). Build the same transaction with the CCC version and compare byte-for-byte. Differences must be explicitly justified. -3. Test the migrated bot in a read-only mode first: build transactions but log them instead of submitting. Compare against what the Lumos version would build. -4. Keep the Lumos version running in parallel during the transition period. - -**Warning signs:** -- Transaction failures on testnet with error codes from `ickb_logic` (5-12), `owned_owner` (5-8), or `limit_order` (5-21) -- The bot producing transactions that succeed on testnet but fail on mainnet (indicating testnet-specific constants leaked) -- Order matching that produces different `ckbDelta`/`udtDelta` values than the Lumos version for the same order pool - -**Phase to address:** -App migration (deferred to future milestone, not in v1 roadmap). The bot is the highest-stakes migration because it runs autonomously and handles real CKB/iCKB value. - ---- - -### Pitfall 5: Molecule Codec Byte Layout Mismatch After Refactoring - -**What goes wrong:** -The TypeScript Molecule codecs (`ReceiptData`, `OwnedOwnerData`, `OrderInfo`, `Ratio`, etc.) use CCC's `@ccc.codec` decorators and `mol.Entity.Base`. These produce byte encodings that must match the Molecule schema at `forks/contracts/schemas/encoding.mol` exactly -- field order, sizes, endianness, padding. A refactoring that reorders fields in a TypeScript class, changes a field type, or inadvertently uses a different encoding for the same semantic value (e.g., `Uint32` vs `Int32` for `owned_distance`) will produce silently different byte encodings. The contracts will reject the transaction or, worse, misinterpret the data. - -Key risk areas: -- `ReceiptData { deposit_quantity: Uint32, deposit_amount: Uint64 }` = 12 bytes. TypeScript uses `@ccc.codec` with fields `depositQuantity` (u32 LE) and `depositAmount` (u64 LE). If someone renames or reorders these fields, the encoded bytes change. -- `OwnedOwnerData { owned_distance: Int32 }` = 4 bytes. Note this is **signed** Int32, not unsigned. Using `Uint32` would encode the same numeric value differently for negative distances. -- Order cell data layout is 89 bytes with a specific structure. The `OrderData` class in `packages/order/src/entities.ts` manually constructs this from components. Any change to the field sizes or offsets breaks order matching. - -**Why it happens:** -TypeScript field names are camelCase, Molecule schema field names are snake_case. There is no compile-time link between them. The mapping is purely by convention and manual code review. When refactoring moves entities to a different file or refactors the class hierarchy, the byte layout can change without any type error. - -**How to avoid:** -1. Add roundtrip codec tests: encode a known TypeScript object, compare to a hardcoded expected hex string, then decode and compare to the original object. -2. Generate the expected hex strings from the Molecule schema directly (or from known Rust test vectors). -3. Never change field order in `@ccc.codec`-decorated classes without verifying the byte layout. -4. Add a comment on each codec class citing the exact Molecule schema line it corresponds to. - -**Warning signs:** -- Any modification to files in `packages/order/src/entities.ts`, `packages/core/src/entities.ts`, or `packages/sdk/src/codec.ts` -- A codec class where the field order differs from the Molecule schema field order -- A cell data `outputData` that decodes to unexpected values in the CCC explorer - -**Phase to address:** -Phase 1 (Library refactor) -- add codec tests as a safety net before any refactoring. - ---- - -### Pitfall 6: Losing the 64-Output NervosDAO Limit Enforcement - -**What goes wrong:** -The NervosDAO script rejects transactions with more than 64 output cells. This limit is currently enforced in 6 separate locations in the codebase: `SmartTransaction.completeFee`, `LogicManager.deposit`, `DaoManager.deposit`, `DaoManager.requestWithdrawal`, `DaoManager.withdraw`, and `apps/bot/src/index.ts`. When SmartTransaction is removed and replaced with utility functions, the `completeFee` check is the most likely to be lost because it is an override that the caller never explicitly invokes -- it runs implicitly when the signer calls `completeFee`. If the replacement utility function does not include this check, transactions built by the SDK will occasionally exceed 64 outputs and fail on-chain in production. - -**Why it happens:** -The 64-output limit is a NervosDAO-specific gotcha that is easy to forget because (a) most transactions have far fewer than 64 outputs, (b) the limit only applies to transactions that include DAO cells, and (c) the error only manifests on-chain, not during local transaction building. The developer testing with small transactions will never hit this limit. The bot operating on mainnet with many deposits/withdrawals will. - -**How to avoid:** -1. When replacing `SmartTransaction.completeFee`, explicitly include the NervosDAO 64-output check in the replacement function. -2. Add an integration test that attempts to build a DAO transaction with 65 outputs and verifies it throws. -3. Consider consolidating the 64-output check into a single utility function (`assertDaoOutputLimit(tx, client)`) called from one place rather than scattered across 6 locations. - -**Warning signs:** -- Removing `SmartTransaction.completeFee` without grepping for `outputs.length > 64` in the codebase -- On-chain failures with NervosDAO error codes only when the bot processes large batches -- Tests passing with small transaction sizes but failing with realistic sizes - -**Phase to address:** -Phase 1 (Library refactor) -- the check must survive the SmartTransaction removal. - ---- - -## Technical Debt Patterns - -Shortcuts that seem reasonable but create long-term problems. - -| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable | -|----------|-------------------|----------------|-----------------| -| Keeping SmartTransaction "just for now" while migrating apps | Apps work immediately without library changes | Two transaction models coexist, every new feature must work with both, CCC upgrades become harder | Never -- library refactor must come before app migration | -| Passing `SmartTransaction` type through public API boundaries | Avoids rewriting callers | External consumers inherit a dependency on a non-standard Transaction subclass, blocking npm publication | Never for published packages -- internal-only is acceptable during transition | -| Skipping codec roundtrip tests | Faster initial development | Silent byte-level bugs that only manifest on-chain | Never -- these tests are cheap to write and prevent catastrophic failures | -| Duplicating CCC utility functions locally instead of adopting upstream | Avoids dependency on specific CCC version | Drift between local and upstream implementations, double maintenance burden | Only if CCC version is not yet released (use `forks/ccc/` local builds to validate, then switch to published version) | -| Migrating bot without parallel Lumos fallback | Cleaner codebase, single transaction path | If CCC-based bot has subtle bugs, no way to fall back; real funds at risk | Never for mainnet -- always keep Lumos bot runnable until CCC bot is validated on testnet | -| Removing `@ickb/lumos-utils` and `@ickb/v1-core` from workspace before all apps are migrated | Simpler dependency tree | Breaks unmigrated apps, blocks incremental migration | Only after ALL apps are migrated and verified | - -## Integration Gotchas - -Common mistakes when connecting to CKB RPC and CCC. - -| Integration | Common Mistake | Correct Approach | -|-------------|----------------|------------------| -| CCC `findCells` vs `findCellsOnChain` | Using cached `findCells` for bot operations where freshness matters | Use `findCellsOnChain` for bot/time-sensitive operations, `findCells` only for UI queries where slight staleness is acceptable | -| CCC `ccc.Transaction.completeFee` | Assuming it handles UDT change automatically | It only handles CKB capacity change. UDT change must be handled separately (this is exactly what SmartTransaction's override added). The replacement must preserve this | -| CCC `Udt.completeInputsByBalance` | Assuming it works for iCKB multi-representation value | CCC's `Udt` only counts xUDT `u128 LE` balances. Receipt cells and deposit cells are invisible to it. Use iCKB-specific logic for iCKB value accounting | -| CCC `ccc.Client` header caching | Assuming headers fetched by `client.getHeaderByNumber` are automatically added to `headerDeps` | They are not. Headers must be explicitly added to the transaction's `headerDeps`. SmartTransaction's `addHeaders` did this automatically -- the replacement must too | -| NervosDAO `since` field encoding | Using `ccc.Epoch.toHex()` for the `since` field in withdrawal inputs | The `since` field requires absolute epoch encoding with specific bit layout. Verify against `ccc.epochToHex()` or the NervosDAO RFC. Incorrect encoding causes on-chain rejection | -| Lumos `TransactionSkeleton` immutability | Assuming in-place mutation works (CCC `Transaction` is mutable) | Lumos skeletons are immutable (Immutable.js). Every operation returns a new skeleton. CCC transactions are mutable. Migration code must not mix idioms (e.g., discarding the return value of a Lumos operation) | - -## Performance Traps - -Patterns that work at small scale but fail as the bot processes real volume. - -| Trap | Symptoms | Prevention | When It Breaks | -|------|----------|------------|----------------| -| Sequential `getHeader()` calls in DAO cell construction | Each DAO cell requires 1-2 RPC calls; processing 30 deposits = 60 sequential calls | Prefetch all needed headers in parallel before constructing cells (batch `getHeaderByNumber` calls) | >10 DAO cells per transaction cycle | -| Unbounded header cache in replacement for SmartTransaction.headers | Memory grows indefinitely across bot iterations | Use LRU or TTL-based cache, or create fresh context per transaction | After running for days with many DAO transactions | -| `findOrders` fetching all orders then filtering | The bot fetches ALL on-chain order cells, then filters by matchability | Use more specific RPC filters, or paginate with early termination | >1000 active orders on-chain | -| Re-fetching system state on every bot iteration | Full `getL1State` call fetches tip, deposits, withdrawals, orders each iteration | Cache tip-dependent data with short TTL, only refresh what changed | Bot with <2 second sleep interval | - -## Security Mistakes - -Domain-specific security issues beyond general web security. - -| Mistake | Risk | Prevention | -|---------|------|------------| -| Incorrect exchange rate in migrated code causes user to receive fewer iCKB than expected | Financial loss -- user deposits CKB, receives less iCKB than the contract would calculate | Cross-validation tests between TypeScript and Rust. Never approximate; use exact integer arithmetic | -| Bot private key leaked through error logging during migration | Bot wallet drained -- attacker uses private key to sign transactions | Audit all `console.log` and error handling in migrated bot. Never log `signer`, `key`, or raw env vars. The faucet already has this bug (logs ephemeral key at line 31) | -| Using testnet constants on mainnet after migration | Transactions silently produce wrong results -- wrong script hashes, wrong dep groups | Validate `getConfig("mainnet")` vs `getConfig("testnet")` constants against on-chain state in CI | -| Order matching with negative gain due to rounding error | Bot loses CKB/iCKB on every match cycle | Verify `gain > 0` assertion in migrated `bestMatch`. The current code checks this but the check could be lost during refactoring | - -## UX Pitfalls - -Common user experience mistakes during the interface app migration. - -| Pitfall | User Impact | Better Approach | -|---------|-------------|-----------------| -| Wallet connector behavior change between Lumos and CCC | JoyId users see different connection flow, potential confusion | Test with actual JoyId wallet. CCC's wallet connector API differs from Lumos -- map the exact UX flow | -| Transaction fee estimation differs between Lumos and CCC | Users see different fee amounts than before, may reject transactions | Log fee estimates from both implementations during parallel testing. Align UX copy for fee display | -| Maturity estimates change due to different epoch calculation | Users see different lock-up times, lose trust | Verify maturity calculation against both implementations for the same deposits | -| Loading states during migration | React Query cache invalidation behaves differently with new data fetching | Map `queryKey` structure from Lumos to CCC. Preserve `refetchInterval` and `staleTime` settings | - -## "Looks Done But Isn't" Checklist - -Things that appear complete but are missing critical pieces. - -- [ ] **SmartTransaction removal:** Often missing the `completeFee` UDT handler iteration -- verify that ALL registered UDT handlers have their `completeUdt` called during fee completion -- [ ] **SmartTransaction removal:** Verify that DAO profit accounting delegates to CCC's native `Transaction.getInputsCapacity()` (which handles DAO profit via `getInputsCapacityExtra()` → `Cell.getDaoProfit()`) rather than reimplementing it locally -- [ ] **SmartTransaction removal:** Often missing the shared-map semantics of `clone()` -- verify that cloned transactions share the same `udtHandlers` and `headers` maps -- [ ] **Bot migration:** Often missing the witness structure for DAO withdrawals -- verify `inputType` witness field contains the header index for each withdrawal request -- [ ] **Bot migration:** Often missing the `same-size` lock args constraint -- verify that withdrawal request lock args have the same byte length as the deposit lock args (required by `OwnedOwner` contract) -- [ ] **Interface migration:** Often missing the React Query cache key migration -- verify that changing the data-fetching layer does not cause stale data or missing cache invalidation -- [ ] **Codec refactoring:** Often missing signed vs unsigned integer encoding -- verify `OwnedOwnerData.owned_distance` uses `Int32` (signed), not `Uint32` -- [ ] **Library API cleanup:** Often missing re-export paths -- verify that consumers importing from `@ickb/utils` still get all needed types after refactoring internal module structure -- [ ] **CCC alignment:** Often missing deprecation warnings -- verify that any `@deprecated` CCC APIs used locally (`udtBalanceFrom`, `ErrorTransactionInsufficientCoin`) are migrated to their replacements - -## Recovery Strategies - -When pitfalls occur despite prevention, how to recover. - -| Pitfall | Recovery Cost | Recovery Steps | -|---------|---------------|----------------| -| Conservation law violation on testnet | LOW | Identify which term of the conservation law is wrong (xUDT, receipts, or deposits). Compare TypeScript calculation against manual computation from block headers. Fix and retest. No on-chain damage -- testnet CKB is free | -| Conservation law violation on mainnet | MEDIUM | Immediately stop bot. Transactions are rejected on-chain so no funds are lost. But pending orders may be stuck until a working bot version is deployed. Rollback to Lumos bot while fixing | -| Exchange rate divergence discovered in production | HIGH | Stop bot. Audit all recent transactions for incorrect iCKB amounts. If users received fewer iCKB than expected, the protocol's conservation law would have prevented the transaction -- so this is actually caught on-chain. The real risk is the bot failing repeatedly and missing matching opportunities | -| 64-output limit hit in production | LOW | Transaction is rejected on-chain, no funds lost. Fix the limit check, redeploy. The bot will retry on next cycle | -| Molecule codec mismatch | HIGH | All transactions using the affected codec fail on-chain. If the codec was used for publishing order data, existing orders may become unmatchable. Must deploy fix immediately and potentially recreate affected orders | -| SmartTransaction removal breaks header caching | MEDIUM | Transactions fail with "Header not found in HeaderDeps". Add headers back to the transaction context. May need to re-add sequential header fetching temporarily until batch prefetching is implemented | - -## Pitfall-to-Phase Mapping - -How roadmap phases should address these pitfalls. - -| Pitfall | Prevention Phase | Verification | -|---------|------------------|--------------| -| SmartTransaction implicit behaviors lost | Phase 1 (Library refactor) | Characterization tests pass: `completeFee` output matches, `getInputsCapacity` return matches, headers present in `headerDeps` | -| CCC Udt subclassing for multi-representation value | Phase 3 (CCC Udt Integration Investigation) | Design decision documented: subclass viability confirmed or fallback approach chosen; conservation law preservation verified in either case | -| Exchange rate divergence | Phase 1 (Library refactor, test infrastructure) | Cross-validation test suite exists with known Rust contract outputs; tests pass in CI | -| Conservation law violation during app migration | Future milestone (App migration) | Migrated bot produces byte-identical transactions to Lumos bot for the same inputs; testnet validation passes | -| Molecule codec byte layout mismatch | Phase 1 (Library refactor, test infrastructure) | Codec roundtrip tests exist for all 6 entity types; expected hex strings match Molecule schema | -| 64-output NervosDAO limit lost | Phase 1 (Library refactor) | Integration test that builds a 65-output DAO transaction and verifies it throws; `assertDaoOutputLimit` utility exists | -| Lumos removal breaks unmigrated apps | Future milestone (App migration) | Each app is migrated and verified individually; Lumos dependencies removed only after all apps pass | -| Private key logging in migrated code | Future milestone (App migration) | Security audit of all `console.log` calls in migrated apps; no sensitive data in logs | -| React Query cache invalidation in interface | Future milestone (App migration, interface) | Manual testing with JoyId wallet; query key structure documented; refetch intervals preserved | - -## Sources - -- Direct codebase analysis: `packages/utils/src/transaction.ts` (SmartTransaction, 517 lines), `packages/utils/src/udt.ts` (UdtManager, 393 lines), `packages/core/src/udt.ts` (IckbUdtManager, 213 lines) -- CCC `Udt` class source: `forks/ccc/packages/udt/src/udt/index.ts` (1798 lines) -- On-chain contract source: `forks/contracts/scripts/contracts/ickb_logic/src/entry.rs` (conservation law, exchange rate) -- On-chain contract source: `forks/contracts/scripts/contracts/owned_owner/` (owner/owned pairing) -- On-chain contract source: `forks/contracts/scripts/contracts/limit_order/` (order/master relationship) -- Molecule schema: `forks/contracts/schemas/encoding.mol` (byte layout definitions) -- NervosDAO RFC: https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0023-dao-deposit-withdraw/0023-dao-deposit-withdraw.md (64-output limit) -- `.planning/PROJECT.md` -- project requirements and constraints -- `.planning/codebase/CONCERNS.md` -- known tech debt and fragile areas -- `.planning/codebase/INTEGRATIONS.md` -- CCC API surface and contract details - ---- -*Pitfalls research for: CKB/CCC library migration (iCKB Stack v2)* -*Researched: 2026-02-21* diff --git a/.planning/research/STACK.md b/.planning/research/STACK.md deleted file mode 100644 index c9bf9dc..0000000 --- a/.planning/research/STACK.md +++ /dev/null @@ -1,329 +0,0 @@ -# Stack Research - -**Domain:** CCC API adoption for iCKB protocol library migration -**Researched:** 2026-02-21 -**Confidence:** HIGH (primary source: local CCC source code in `forks/ccc/`) - -## Context - -This research focuses on the CCC APIs and patterns that should be adopted as part of the iCKB stack v2 migration. The existing TypeScript/pnpm/CCC stack is established and does not need re-research. This document identifies specific CCC APIs to adopt, local utilities to replace, and patterns to follow for the SmartTransaction removal, UDT handling adoption, and CCC alignment audit. - -## Recommended Stack Changes - -### CCC APIs to Adopt (replacing local implementations) - -| CCC API | Replaces | Package(s) Affected | Confidence | -|---------|----------|---------------------|------------| -| `ccc.Transaction.completeFeeChangeToLock()` | `SmartTransaction.completeFee()` for CKB change | `@ickb/utils`, all consumers | HIGH | -| `ccc.Transaction.completeFeeBy()` | `SmartTransaction.completeFee()` convenience | `@ickb/utils`, all consumers | HIGH | -| `ccc.Transaction.completeFeeChangeToOutput()` | N/A (new capability) | Order matching, bot | HIGH | -| `ccc.Transaction.completeInputsByCapacity()` | `CapacityManager.findCapacities()` + manual add | `@ickb/utils` | HIGH | -| `ccc.Transaction.completeInputsAll()` | Custom collect-all patterns | `@ickb/utils` | HIGH | -| `ccc.Transaction.completeInputs()` | Custom accumulator patterns | `@ickb/utils` | HIGH | -| `ccc.Transaction.getInputsCapacity()` | `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | -| `ccc.Transaction.getOutputsCapacity()` | Direct usage (already available) | All packages | HIGH | -| `ccc.Transaction.getFee()` | Manual fee calculation | All packages | HIGH | -| `@ckb-ccc/udt` `Udt` class | `UdtManager` class | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.completeInputsByBalance()` | `UdtManager.completeUdt()` input portion | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.completeChangeToLock()` | `UdtManager.completeUdt()` change portion | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.completeBy()` | Convenience UDT completion | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.complete()` | Custom UDT completion with change function | `@ickb/core` (IckbUdtManager) | HIGH | -| `Udt.getInputsBalance()` / `Udt.getInputsInfo()` | `UdtManager.getInputsUdtBalance()` | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.getOutputsBalance()` / `Udt.getOutputsInfo()` | `UdtManager.getOutputsUdtBalance()` | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.balanceFromUnsafe()` | `ccc.udtBalanceFrom()` (deprecated) | All packages using UDT balance | HIGH | -| `Udt.infoFrom()` | Manual per-cell UDT info aggregation | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.isUdt()` | `UdtManager.isUdt()` | `@ickb/utils`, `@ickb/core` | HIGH | -| `Udt.addCellDeps()` | `SmartTransaction.addUdtHandlers()` cell dep portion | All packages | HIGH | -| `UdtInfo` class | `[ccc.FixedPoint, ccc.FixedPoint]` tuple | `@ickb/utils`, `@ickb/core` | HIGH | -| `ErrorUdtInsufficientCoin` (from `@ckb-ccc/udt`) | `ErrorTransactionInsufficientCoin` (local) | `@ickb/utils` | HIGH | -| `ccc.numMax()` / `ccc.numMin()` | Local `max()` / `min()` for bigint | `@ickb/utils` | HIGH | -| `ccc.gcd()` | Local `gcd()` | `@ickb/utils` | HIGH | -| `ccc.isHex()` | Local `isHex()` | `@ickb/utils` | HIGH | -| `ccc.hexFrom()` | Local `hexFrom()` (partial -- CCC's takes `HexLike` not `bigint | Entity`) | `@ickb/utils` | MEDIUM | -| `ccc.reduce()` / `ccc.reduceAsync()` | Already adopted | N/A | HIGH | -| `ccc.Epoch` | Already adopted (local deleted) | N/A | HIGH | -| `ccc.Cell.getDaoProfit()` | Manual DAO profit calculation in `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | -| `ccc.CellInput.getExtraCapacity()` | Manual extra capacity in `SmartTransaction.getInputsCapacity()` | `@ickb/utils` | HIGH | -| `ccc.Cell.getNervosDaoInfo()` | Manual header fetching for deposit/withdrawal | `@ickb/dao` | HIGH | -| `ccc.CellAny` | N/A (use for output cell representation) | All packages | HIGH | -| `ccc.CellOutput.from(output, outputData)` | Manual capacity calculation | All packages | HIGH | -| `ccc.Client.cache` | `SmartTransaction.headers` map | `@ickb/utils` | HIGH | - -### Local Utilities to KEEP (no CCC equivalent) - -| Utility | Location | Why Keep | -|---------|----------|----------| -| `binarySearch()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | -| `asyncBinarySearch()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | -| `shuffle()` | `packages/utils/src/utils.ts` | Domain-specific, no CCC equivalent | -| `unique()` | `packages/utils/src/utils.ts` | Works on `ccc.Entity` with `.eq()`, CCC has no equivalent | -| `collect()` | `packages/utils/src/utils.ts` | Async generator collector, no CCC equivalent | -| `BufferedGenerator` | (if exists) | Batched async iteration, no CCC equivalent | -| `MinHeap` | `packages/utils/src/heap.ts` | Data structure, no CCC equivalent | -| `sum()` | `packages/utils/src/utils.ts` | Generic sum, no CCC equivalent | -| `ScriptDeps` interface | `packages/utils/src/utils.ts` | iCKB-specific manager composition pattern | -| `ValueComponents` interface | `packages/utils/src/utils.ts` | iCKB-specific dual-value abstraction | -| `ExchangeRatio` interface | `packages/utils/src/utils.ts` | iCKB-specific exchange rate abstraction | - -### CCC `@ckb-ccc/udt` Package - -**Version:** Local build from `forks/ccc/packages/udt/` -**Key classes:** `Udt`, `UdtInfo`, `UdtConfig`, `ErrorUdtInsufficientCoin` -**Depends on:** `@ckb-ccc/core`, `@ckb-ccc/ssri` - -Use `@ckb-ccc/udt` because: -1. It provides the complete UDT lifecycle: cell finding, balance calculation, input completion, change handling, transfer, mint -2. It is designed for subclassing -- `infoFrom()` and `balanceFrom()` are virtual methods that subclasses can override -3. It tracks both UDT balance AND capacity per cell via `UdtInfo` (balance, capacity, count), matching iCKB's need for dual-value tracking -4. The `complete()` method's two-phase change function (shouldModify=false for capacity estimation, shouldModify=true for mutation) is the correct pattern for iCKB's complex UDT handling - -**SSRI dependency note:** `Udt` extends `ssri.Trait`. For iCKB's use case (legacy xUDT, not SSRI-compliant), the executor will be `undefined`. This is explicitly supported -- the `Udt` class falls back to direct cell manipulation when no executor is provided. - -## SmartTransaction Removal Strategy - -### What SmartTransaction Does Today (and CCC Replacements) - -| SmartTransaction Feature | CCC Native Replacement | Notes | -|--------------------------|------------------------|-------| -| UDT handler management (`udtHandlers` map) | `Udt` instances per UDT type | Udt instances are standalone; no need for a map on the transaction | -| `completeFee()` override (UDT + CKB change) | `Udt.completeBy()` then `tx.completeFeeBy()` | Two-step: complete UDT first, then CKB fee | -| `getInputsUdtBalance()` override | `Udt.getInputsBalance()` | Direct method on Udt instance | -| `getOutputsUdtBalance()` override | `Udt.getOutputsBalance()` | Direct method on Udt instance | -| `getInputsCapacity()` override (DAO profit) | `ccc.Transaction.getInputsCapacity()` | CCC's base implementation now calls `getExtraCapacity()` per input, which includes DAO profit via `Cell.getDaoProfit()` | -| Header caching (`headers` map) | `ccc.Client.cache` (ClientCacheMemory) | Headers cached automatically by Client on fetch | -| `addHeaders()` / `getHeader()` | Removed. Call sites inline CCC client calls (`client.getTransactionWithHeader()`, `client.getHeaderByNumber()`); `addHeaders()` call sites push to `tx.headerDeps` directly | CCC caches confirmed headers | -| `addUdtHandlers()` | `udt.addCellDeps(tx)` | Cell deps added directly by Udt instance | -| `default()` factory | `ccc.Transaction.default()` | Same pattern, no extra state | -| `clone()` with shared state | `ccc.Transaction.clone()` | No shared state needed without udtHandlers/headers maps | -| `fromLumosSkeleton()` | `ccc.Transaction.fromLumosSkeleton()` | Base class method, still available | - -### Critical Design Decision: Header Caching - -SmartTransaction's `headers` map served two purposes: -1. **Performance:** Avoid re-fetching headers -2. **Correctness:** Ensure headers are in `headerDeps` when needed for DAO calculations - -CCC's `Client.cache` handles purpose (1) -- all `getHeaderByHash()` and `getHeaderByNumber()` calls are cached if the header is confirmed. Purpose (2) -- adding to `headerDeps` -- is handled by inlining CCC client calls at each call site. - -**Decision (from Phase 1 context):** `getHeader()` function and `HeaderKey` type are removed entirely from `@ickb/utils`. Call sites inline CCC client calls: `txHash` lookups use `(await client.getTransactionWithHeader(hash))?.header`, `number` lookups use `await client.getHeaderByNumber(n)`. `addHeaders()` call sites in DaoManager/LogicManager push to `tx.headerDeps` directly. - -### Critical Design Decision: DAO Profit in getInputsCapacity - -CCC's `Transaction.getInputsCapacity()` now includes DAO profit via `CellInput.getExtraCapacity()` -> `Cell.getDaoProfit()`. This means SmartTransaction's override of `getInputsCapacity()` is **no longer needed** -- CCC does this natively. - -Verified in CCC source (`forks/ccc/packages/core/src/ckb/transaction.ts` lines 1860-1883): -```typescript -async getInputsCapacity(client: Client): Promise { - return ( - (await reduceAsync( - this.inputs, - async (acc, input) => { - const { cellOutput: { capacity } } = await input.getCell(client); - return acc + capacity; - }, - Zero, - )) + (await this.getInputsCapacityExtra(client)) - ); -} -``` - -Where `getInputsCapacityExtra` sums `getExtraCapacity()` per input, which calls `Cell.getDaoProfit()`. - -## IckbUdtManager -> CCC Udt Subclass Migration - -### Current IckbUdtManager - -`IckbUdtManager` extends `UdtManager` (local) and overrides `getInputsUdtBalance()` to account for iCKB's three value representations: -1. **xUDT cells** -- standard UDT balance from output data -2. **Receipt cells** -- iCKB value calculated from deposit amount and header's accumulated rate -3. **Deposit cells being withdrawn** -- negative iCKB value (burning UDT to withdraw deposit) - -### Recommended Approach: Subclass `Udt` from `@ckb-ccc/udt` - -Create `IckbUdt extends Udt` that overrides `infoFrom()` to recognize all three representations. - -**Why `infoFrom()` (updated in Phase 3 research):** -- `infoFrom()` is called by all balance/info methods, so overriding it propagates everywhere. Input cells passed via `getInputsInfo()` → `CellInput.getCell()` always have `outPoint` set on the `CellAny`/`Cell` objects, enabling header fetches for receipt/deposit value calculation. Output cells from `tx.outputCells` lack `outPoint`, allowing `infoFrom` to distinguish inputs from outputs. -- `CellAny` has `capacityFree` (transaction.ts:404-405), so deposit cell valuation works directly. Only `DaoManager.isDeposit()` requires constructing a `Cell` from `CellAny`. -- CCC's `completeInputsByBalance()` chains through `getInputsInfo()` → `infoFrom()`, so overriding `infoFrom` changes balancing behavior correctly without duplicating resolution logic. - -**Why NOT override `completeInputsByBalance()`:** -- The base implementation's dual-constraint logic (balance + capacity) is correct for iCKB -- The subclass only needs to change HOW balance is calculated from cells, not the input selection strategy - -**Implementation sketch:** See 03-RESEARCH.md for the `infoFrom()` override pattern. ARCHITECTURE.md "CCC Udt Adoption for iCKB" section has the same corrected example. - -**Header fetching within `infoFrom()` override:** - -Since input cells have `outPoint` set (resolved via `CellInput.getCell(client)` in `getInputsInfo`), the `infoFrom` override can fetch headers using: - -1. **`client.getTransactionWithHeader(cell.outPoint.txHash)`** -- Fetches the block header for the transaction that created the cell. Cached by CCC Client. Returns `{ transaction, header? }`. - -2. **`client.getTransaction()` + `client.getHeaderByHash()`** -- Alternative two-step approach: get the transaction response (which includes `blockHash`), then fetch the header. Both are cached by CCC Client. - -Option 1 is simpler and sufficient for the `infoFrom()` override. - -## CCC Transaction Completion Pattern - -### Old Pattern (SmartTransaction) - -```typescript -const tx = SmartTransaction.default(); -tx.addUdtHandlers(ickbUdtHandler); -// ... add outputs ... -await tx.completeFee(signer, changeLock, feeRate); -// completeFee internally calls handler.completeUdt() for each UDT, -// then super.completeFee() for CKB -``` - -### New Pattern (plain ccc.Transaction + Udt instances) - -```typescript -const tx = ccc.Transaction.default(); -// ... add outputs ... - -// Step 1: Complete UDT inputs and change -const completedTx = await ickbUdt.completeBy(tx, signer); -// OR for more control: -// const completedTx = await ickbUdt.completeChangeToLock(tx, signer, changeLock); - -// Step 2: Complete CKB capacity inputs -await completedTx.completeInputsByCapacity(signer); - -// Step 3: Complete fee with CKB change -await completedTx.completeFeeBy(signer); -// OR: await completedTx.completeFeeChangeToLock(signer, changeLock); -``` - -**Why this order matters:** -1. UDT completion first because UDT cells also contribute CKB capacity -2. CKB capacity second to cover any remaining capacity needs -3. Fee completion last because it needs the final transaction size - -This matches the pattern shown in CCC's own `Udt.transfer()` example (lines 900-904 of udt source): -```typescript -const completedTx = await udt.completeBy(tx, signer); -await completedTx.completeInputsByCapacity(signer); -await completedTx.completeFeeBy(signer); -``` - -## Utility Replacement Details - -### Replace Local `hexFrom()` (MEDIUM confidence) - -Local `hexFrom(v: bigint | ccc.Entity | ccc.BytesLike)` handles three input types: -- `bigint` -> hex string via `numToHex` -- `ccc.Entity` -> hex via `.toBytes()` then `ccc.hexFrom()` -- `ccc.BytesLike` -> delegates to `ccc.hexFrom()` - -CCC's `hexFrom(hex: HexLike)` only handles `HexLike` (which is `BytesLike`). The local version adds `bigint` and `Entity` support. - -**Recommendation:** Keep local `hexFrom()` but rename it to avoid confusion. Or split into explicit calls: use `ccc.numToHex()` for bigint, `ccc.hexFrom(entity.toBytes())` for entities. The split approach is clearer and avoids maintaining a custom wrapper. - -### Replace Local `max()`/`min()` (HIGH confidence) - -Local `max()` and `min()` are generic (work with any comparable type). CCC's `numMax()`/`numMin()` are bigint-specific. - -**Recommendation:** Use `ccc.numMax()`/`ccc.numMin()` for all bigint comparisons (which is the only use case in this codebase). Delete local `max()`/`min()` since they are only used with bigint. - -### Replace Local `gcd()` (HIGH confidence) - -Local `gcd()` accepts variadic `bigint` args. CCC's `gcd()` accepts two `NumLike` args. - -**Recommendation:** Use `ccc.gcd()` with `.reduce()` for variadic case. Or keep local wrapper if variadic is used extensively. - -### Replace Local `isHex()` (HIGH confidence) - -Both implementations are functionally equivalent (check for `0x` prefix, even length, valid hex chars). - -**Recommendation:** Use `ccc.isHex()` directly. Delete local `isHex()`. - -## What NOT to Use - -| Avoid | Why | Use Instead | -|-------|-----|-------------| -| `SmartTransaction` class | Abandoned ecosystem concept; all its features now exist in CCC natively | `ccc.Transaction` + `Udt` instances | -| `UdtHandler` interface | Coupled to SmartTransaction; CCC's `Udt` class provides richer equivalent | `Udt` class from `@ckb-ccc/udt` | -| `UdtManager` class | Replaced by CCC's `Udt` class which has the same capabilities + more | `Udt` from `@ckb-ccc/udt` | -| `CapacityManager` for input completion | CCC's `Transaction.completeInputsByCapacity()` does this natively | `tx.completeInputsByCapacity(signer)` | -| `CapacityManager` for cell finding | CCC's `Client.findCellsByLock()` and `Signer.findCells()` handle this | `client.findCellsByLock()` or `signer.findCells()` | -| `ccc.udtBalanceFrom()` | Deprecated in CCC core; marked with `@deprecated` annotation | `Udt.balanceFromUnsafe()` from `@ckb-ccc/udt` | -| `ccc.Transaction.getInputsUdtBalance()` | Deprecated in CCC core | `Udt.getInputsBalance()` from `@ckb-ccc/udt` | -| `ccc.Transaction.getOutputsUdtBalance()` | Deprecated in CCC core | `Udt.getOutputsBalance()` from `@ckb-ccc/udt` | -| `ccc.Transaction.completeInputsByUdt()` | Deprecated in CCC core | `Udt.completeInputsByBalance()` from `@ckb-ccc/udt` | -| `SmartTransaction.headers` map | Header caching now handled by `Client.cache` | Let CCC Client cache handle it | -| Manual header dep management for DAO | CCC's `getInputsCapacity()` handles DAO profit natively | Use CCC's built-in DAO profit calculation | -| `@ckb-lumos/*` packages | Being entirely replaced by CCC | CCC equivalents for all Lumos functionality | -| `@ickb/lumos-utils` | Legacy iCKB Lumos utilities being replaced | `@ickb/utils` + CCC | -| `@ickb/v1-core` | Legacy iCKB core being replaced | `@ickb/core` + CCC | - -## CapacityManager Fate - -`CapacityManager` currently has two roles: -1. **Cell finding** -- `findCapacities()` async generator -2. **Cell adding** -- `addCapacities(tx, cells)` helper - -Both are now redundant: -- Cell finding: `ccc.Transaction.completeInputsByCapacity(signer)` handles capacity collection and input addition in one step -- Cell adding: `ccc.Transaction.addInput(cell)` is the native method - -**However,** `CapacityManager` is used by the faucet app for a specific pattern: find cells matching a lock, then transfer them. This pattern could use `signer.findCells()` with a filter instead. - -**Recommendation:** Remove `CapacityManager` after verifying that `completeInputsByCapacity()` covers all use cases. For the faucet's cell-discovery-then-transfer pattern, use CCC's `client.findCellsByLock()` directly. - -## PR #328 (FeePayer) Status - -PR #328 proposes a `FeePayer` abstraction for CCC that would allow specifying who pays transaction fees. This is relevant because SmartTransaction's fee completion could designate a specific lock for fee payment. - -**Current status (updated):** PR #328 is now integrated into `forks/ccc` via the .pin/record system. FeePayer classes are available at `forks/ccc/packages/core/src/signer/feePayer/`. The user decided during Phase 3 context that PR #328 is the target architecture -- investigation should design around it. - -**Impact on migration:** The FeePayer abstraction is available to build against directly. The `infoFrom()` override is compatible with both the current Signer-based completion and the FeePayer-based completion -- cells flow through `getInputsInfo` → `infoFrom` regardless of which completion plumbing is used. - -**Recommendation:** Design around FeePayer as the target architecture. Use `completeFeeChangeToLock()` / `completeFeeBy()` for current execution while investigating how FeePayer's `completeInputs(tx, filter, accumulator, init)` pattern can improve iCKB's receipt/deposit cell discovery. - -## Version Compatibility - -| Package | Compatible With | Notes | -|---------|-----------------|-------| -| `@ckb-ccc/core` ^1.12.2 | `@ckb-ccc/udt` (local build) | Both from same CCC build; version-locked via catalog | -| `@ckb-ccc/udt` | `@ckb-ccc/ssri` | `Udt` extends `ssri.Trait`; comes from same CCC build | -| `@ckb-ccc/core` ^1.12.2 | Node.js >= 24 | CCC uses standard APIs; no Node.js compatibility issues | -| `@ckb-ccc/ccc` ^1.1.21 | `apps/interface` | Full bundle with wallet connectors; separate from core | - -**New dependency for packages:** `@ckb-ccc/udt` must be added to packages that subclass `Udt`. Currently only `@ickb/core` needs this (for `IckbUdt`). The `@ickb/utils` package may also need it if `UdtManager` is replaced with re-exports from `@ckb-ccc/udt`. - -## Installation Changes - -```bash -# New dependency for @ickb/core (and potentially @ickb/utils) -# Added to pnpm-workspace.yaml catalog: -# '@ckb-ccc/udt': ^1.x.x (version aligned with @ckb-ccc/core) - -# Per-package: -# @ickb/core: add @ckb-ccc/udt to dependencies -# @ickb/utils: potentially add @ckb-ccc/udt if re-exporting Udt types - -# No other new dependencies needed -- all other changes use existing @ckb-ccc/core APIs -``` - -**Note:** With `forks/ccc/` local build active, `.pnpmfile.cjs` automatically rewires all `@ckb-ccc/*` dependencies to local packages, so the `@ckb-ccc/udt` package is already available from the local CCC build. - -## Sources - -- `forks/ccc/packages/udt/src/udt/index.ts` -- CCC Udt class, full source (1798 lines) -- HIGH confidence -- `forks/ccc/packages/core/src/ckb/transaction.ts` -- CCC Transaction class, full source (2537 lines) -- HIGH confidence -- `forks/ccc/packages/core/src/client/client.ts` -- CCC Client class with caching, cell finding -- HIGH confidence -- `forks/ccc/packages/core/src/num/index.ts` -- `numMax`, `numMin`, `numFrom` etc. -- HIGH confidence -- `forks/ccc/packages/core/src/hex/index.ts` -- `isHex`, `hexFrom`, `bytesLen` -- HIGH confidence -- `forks/ccc/packages/core/src/utils/index.ts` -- `reduce`, `reduceAsync`, `gcd`, `apply`, `sleep` -- HIGH confidence -- `forks/ccc/packages/core/src/ckb/epoch.ts` -- `Epoch` class (already adopted) -- HIGH confidence -- `packages/utils/src/transaction.ts` -- Current SmartTransaction implementation (517 lines) -- HIGH confidence -- `packages/utils/src/udt.ts` -- Current UdtManager/UdtHandler implementation (393 lines) -- HIGH confidence -- `packages/utils/src/capacity.ts` -- Current CapacityManager implementation (221 lines) -- HIGH confidence -- `packages/core/src/udt.ts` -- Current IckbUdtManager implementation (213 lines) -- HIGH confidence -- `.planning/PROJECT.md` -- Project context and requirements -- HIGH confidence -- `.planning/codebase/STACK.md` -- Current stack analysis -- HIGH confidence - ---- -*Stack research for: CCC API adoption in iCKB migration* -*Researched: 2026-02-21* diff --git a/.planning/research/SUMMARY.md b/.planning/research/SUMMARY.md deleted file mode 100644 index d99ad1a..0000000 --- a/.planning/research/SUMMARY.md +++ /dev/null @@ -1,196 +0,0 @@ -# Project Research Summary - -**Project:** iCKB Stack v2 — CCC API Migration -**Domain:** CKB blockchain protocol library suite (NervosDAO liquid staking / iCKB) -**Researched:** 2026-02-21 -**Confidence:** HIGH - -## Executive Summary - -The iCKB library suite is a unique CKB protocol library — there are no direct competitors. It handles NervosDAO liquid staking via the iCKB xUDT token, featuring multi-representation value tracking (UDT tokens + receipt cells + DAO deposit cells), limit order matching, and delegated withdrawal management. The established TypeScript/pnpm/CCC stack is sound. The entire migration centers on one architectural pivot: removing `SmartTransaction` (a `ccc.Transaction` subclass abandoned by the broader CCC ecosystem) and replacing its responsibilities with plain `ccc.Transaction` combined with CCC-native APIs — specifically the `@ckb-ccc/udt` package's `Udt` class and the transaction completion methods added to CCC core (`completeFeeBy`, `completeInputsByCapacity`, `completeFeeChangeToLock`). - -The recommended approach is a strict bottom-up refactoring that proceeds through the dependency graph: `@ickb/utils` (remove SmartTransaction/UdtHandler/UdtManager) → `@ickb/dao` and `@ickb/order` (update to plain `ccc.Transaction`) → `@ickb/core` (create `IckbUdt extends udt.Udt` with iCKB-specific balance overrides) → `@ickb/sdk` (explicit completion pipeline) → apps (bot, interface, tester migrated from Lumos). CCC's `Udt` class covers standard xUDT operations; iCKB's triple-representation value logic must remain in `IckbUdt` and must NOT be delegated to a generic Udt subclass that changes how `completeInputsByBalance` selects cells. - -The primary risk is losing implicit behaviors baked into `SmartTransaction` — particularly the DAO-profit-aware `getInputsCapacity` override, the 64-output NervosDAO limit check inside `completeFee`, and the UDT handler dispatch loop that runs before CKB fee completion. All three of these are silent, non-obvious behaviors that a mechanical find-and-replace will miss. The mitigation is straightforward: catalog every SmartTransaction-specific method, write characterization tests before touching anything, and add codec roundtrip tests to prevent byte-level regressions in the Molecule encodings that the on-chain contracts enforce. - -## Key Findings - -### Recommended Stack - -The existing TypeScript/pnpm/CCC stack requires no new technology choices. The migration is a CCC API adoption exercise: replace 14 local utilities with CCC equivalents (`ccc.numMax`/`numMin`, `ccc.gcd`, `ccc.isHex`, `Udt.balanceFromUnsafe`, etc.), add `@ckb-ccc/udt` as a dependency to `@ickb/core`, and restructure transaction building around CCC's native completion pipeline. The local `forks/ccc/` build system already makes `@ckb-ccc/udt` available via `.pnpmfile.cjs` rewriting — no additional infrastructure work needed. - -**Core technologies:** -- `@ckb-ccc/core` ^1.12.2: Transaction building, cell queries, signer abstraction — already adopted, native replacement for all SmartTransaction behaviors -- `@ckb-ccc/udt` (local forks/ccc build): UDT lifecycle management (cell finding, balance calculation, input completion, change handling) — replaces local UdtManager/UdtHandler; `IckbUdt` subclasses this -- `ccc.Transaction.completeFeeBy` / `completeFeeChangeToLock`: CKB fee completion — direct SmartTransaction.completeFee replacement for the CKB-change portion -- `ccc.Transaction.completeInputsByCapacity`: CKB capacity input collection — replaces CapacityManager's cell-finding role -- `ccc.Client.cache`: Transparent header caching — replaces SmartTransaction's `headers` map for performance; header deps must still be added explicitly - -**Do NOT use:** -- `SmartTransaction`: Abandoned ecosystem pattern; all capabilities now exist in CCC natively -- `UdtHandler` / `UdtManager`: Parallel type system absorbed by CCC's `Udt` class -- `CapacityManager` (for input completion): `tx.completeInputsByCapacity(signer)` does this in one call -- Deprecated CCC APIs: `ccc.udtBalanceFrom()`, `ccc.Transaction.getInputsUdtBalance()`, `ccc.Transaction.completeInputsByUdt()` - -### Expected Features - -**Must have (table stakes — blocks npm publication):** -- SmartTransaction removal (TS-1) — the critical path; all other work depends on it -- CCC utility deduplication (TS-2) — adopt CCC equivalents, keep iCKB-unique utilities -- Clean public API surface (TS-3) — audit exports, mark internals, curate index.ts files -- Bot migration (TS-5) — validates entire library stack under real production conditions -- Multi-representation UDT preservation (D-1) — iCKB balance logic must survive removal intact -- npm publication with provenance (TS-11) — already configured, depends on clean API - -**Should have (add after bot migration validates the library):** -- Interface app migration (TS-6) — same UI, swap Lumos internals for CCC + new packages -- Tester app migration (TS-7) — validates all transaction paths in simulation -- Complete Lumos removal (TS-4) — remove `@ickb/lumos-utils`, `@ickb/v1-core`, all `@ckb-lumos/*`; gate on all apps migrated -- CCC Udt subclassing investigation (D-2) — exploratory; informs long-term architecture -- Type export audit (TS-12) — after public API stabilizes - -**Defer (v2+):** -- Upstream CCC contributions (D-9) — continue tracking FeePayer PR #328; adopt if merged -- Additional UDT type support — generalize pattern if other xUDT tokens need multi-representation handling -- Pool snapshot encoding improvements — only if bot requirements grow beyond current capacity - -The library already implements all differentiators (D-3 through D-8, D-10): maturity estimation, pool snapshots, async generator cell discovery, composable ScriptDeps pattern, deterministic exchange rates, limit order lifecycle, delegated withdrawals. These must survive the migration unchanged. - -### Architecture Approach - -The architecture shifts from a God-object transaction (SmartTransaction carrying UDT handlers + header cache + overridden behaviors) to a layered composition model: plain `ccc.Transaction` for state, standalone utility functions for concerns like header dep management, `IckbUdt extends udt.Udt` for iCKB-specific balance calculation, and an explicit completion pipeline at the call site (complete UDT first, then CKB capacity, then fee). The build order is strictly bottom-up through the dependency graph. - -**Major components:** -1. `@ickb/utils` — async data utilities (`collect`, `unique`, `binarySearch`, `MinHeap`), codec utilities; NO SmartTransaction, NO UdtHandler, NO UdtManager, NO CapacityManager, NO `getHeader()`/`HeaderKey` after refactor -2. `@ickb/dao` + `@ickb/order` — domain managers operating on plain `ccc.Transaction`; add cell deps directly; no UDT awareness -3. `@ickb/core` — `IckbUdt extends udt.Udt` overriding `infoFrom()` for triple-representation balance; `LogicManager` and `OwnedOwnerManager` for iCKB protocol operations -4. `@ickb/sdk` — `IckbSdk` facade orchestrating all managers; explicit completion pipeline: `ickbUdt.completeBy(tx, signer)` then `tx.completeFeeBy(signer)` -5. Apps (bot, interface, tester) — consume SDK; no direct manager usage for most operations - -**Key pattern — explicit completion pipeline:** -```typescript -const tx = ccc.Transaction.default(); -// domain operations... -const completedTx = await ickbUdt.completeBy(tx, signer); // UDT inputs + change -await completedTx.completeFeeBy(signer); // CKB capacity + fee -await signer.sendTransaction(completedTx); -``` - -**Key architectural decision — override `infoFrom()` (corrected in Phase 3 research):** -`infoFrom()` receives `CellAnyLike` objects — input cells (from `getInputsInfo` → `CellInput.getCell()`) always have `outPoint` set, enabling header fetches for receipt/deposit value calculation. Output cells lack `outPoint`, allowing `infoFrom` to distinguish inputs from outputs. See 03-RESEARCH.md for the corrected design. - -### Critical Pitfalls - -1. **SmartTransaction implicit behaviors lost during removal** — `completeFee` silently iterates all UDT handlers, `getInputsCapacity` adds DAO withdrawal profit, `clone()` shares handler/header maps. A mechanical find-and-replace misses all three. Avoid by: cataloging every SmartTransaction-specific method, writing characterization tests before removing anything, and designing the replacement as explicit utility functions rather than a companion object. - -2. **Incorrect CCC Udt subclassing for multi-representation value** — CCC's `Udt.completeInputsByBalance` assumes UDT balance = sum of `u128 LE` fields in matching type cells. iCKB's conservation law spans xUDT cells, receipt cells, and DAO deposit cells. Avoid by: overriding `infoFrom()` in `IckbUdt` to value all three cell types with correct sign conventions (Phase 3 research confirmed `CellAnyLike` has `outPoint` for input cells, enabling header fetches). Do NOT override `balanceFrom()` for iCKB-specific representations. - -3. **Exchange rate divergence between TypeScript and Rust contract** — The `ickbValue()` formula must produce byte-identical results to the on-chain `ickb_logic` script. Integer division order and the soft-cap formula are dangerous. Avoid by: creating cross-validation tests with known Rust contract outputs BEFORE touching any exchange rate code. - -4. **64-output NervosDAO limit lost from `completeFee`** — This check is buried in SmartTransaction's `completeFee` override and currently enforced in 6 separate locations. Removal without consolidation will cause production failures. Avoid by: extracting a single `assertDaoOutputLimit(tx)` utility called from one canonical location, with an integration test that verifies a 65-output DAO transaction throws. - -5. **Conservation law violation during app migration** — The bot must produce byte-identical transactions to the Lumos version. On-chain contracts enforce position-sensitive rules (owned_distance relative offsets, master_distance in orders, witness structure for DAO withdrawals). Avoid by: migrating in a feature branch, capturing golden transactions from the Lumos bot, comparing byte-for-byte with the CCC version, and keeping the Lumos bot runnable during the testnet validation period. - -6. **Molecule codec byte layout mismatch** — `ReceiptData`, `OwnedOwnerData`, `OrderData` must match the Molecule schema exactly. TypeScript field reordering silently changes byte encoding. Avoid by: adding codec roundtrip tests with hardcoded expected hex strings before any refactoring. - -## Implications for Roadmap - -> **Note:** The phase structure below was a pre-roadmap research suggestion. The actual ROADMAP (`.planning/ROADMAP.md`) uses a different 7-phase feature-slice approach: SmartTransaction Removal → CCC Utility Adoption → Udt Investigation → Deprecated API Replacement → Core UDT Refactor → SDK Completion → Full Verification. App migration (bot, interface, tester) is deferred to a future milestone. The research findings below still inform the roadmap decisions. - -Based on research, suggested phase structure: - -### Phase 1: Library Foundation Refactor -**Rationale:** SmartTransaction removal is the critical path — 100% of downstream work depends on it. Characterization tests and codec tests must come first to create a safety net. CCC utility deduplication is cheap and cleans up the API surface. The dependency graph demands `@ickb/utils` changes before any domain package changes. -**Delivers:** CCC-native library packages with clean public API; no SmartTransaction anywhere; all P1 features ready for npm publication; test infrastructure protecting against regressions. -**Addresses:** TS-1 (SmartTransaction removal), TS-2 (utility deduplication), TS-3 (clean public API), D-1 (multi-representation UDT preservation) -**Avoids:** Pitfalls 1 (SmartTransaction implicit behaviors), 3 (exchange rate divergence), 4 (64-output limit), 6 (codec byte layout) -**Sub-phases (dependency-driven):** -1a. Test infrastructure: characterization tests for SmartTransaction behaviors; codec roundtrip tests; exchange rate cross-validation fixtures -1b. `@ickb/utils`: remove SmartTransaction, CapacityManager, `getHeader()`/`HeaderKey`; adopt CCC utility equivalents -1c. `@ickb/dao` + `@ickb/order` (parallel): update all manager methods from `SmartTransaction` to `ccc.TransactionLike` -1d. `@ickb/core`: create `IckbUdt extends udt.Udt`; update LogicManager/OwnedOwnerManager -1e. `@ickb/sdk`: implement explicit completion pipeline; update IckbSdk facade -**Research flag:** Phase 1d needs careful investigation — the `IckbUdt` subclassing approach is architecturally sound (confirmed by both STACK.md and ARCHITECTURE.md research) but the header-access-in-`getInputsInfo` pattern requires verification against the CCC `Udt` API. - -### Phase 2: Bot Migration and Library Validation -**Rationale:** The bot is the integration test for the entire library. It exercises every transaction type (deposit, withdrawal request, withdrawal, order match, order melt) under real production conditions. Bot migration cannot happen before Phase 1 completes — the bot must target the final library API, not an intermediate state. TS-5 (bot migration) is P1 precisely because it validates the library is production-ready. -**Delivers:** Fully migrated bot running on CCC + new packages; testnet validation complete; npm publication of updated packages. -**Addresses:** TS-5 (bot migration), TS-11 (npm publication) -**Avoids:** Pitfall 4 (conservation law violation during migration), Pitfall 3 (key logging security) -**Research flag:** No additional research needed — the migration pattern is well-documented by existing Lumos bot code and the new library API surface. Standard patterns apply. - -### Phase 3: App Migration and Lumos Removal -**Rationale:** Interface and tester migrations are unblocked only after bot migration proves the library API is stable and correct. Lumos removal is the final gate — can only happen after all three legacy apps are migrated. This phase is lower stakes than Phase 2 (the interface has no autonomous signing; the tester uses simulation mode). -**Delivers:** All 5 apps on CCC; zero Lumos dependencies in the monorepo; complete removal of `@ickb/lumos-utils` and `@ickb/v1-core`. -**Addresses:** TS-6 (interface migration), TS-7 (tester migration), TS-4 (Lumos removal), TS-12 (type export audit) -**Avoids:** UX pitfalls (wallet connector behavior change, fee estimation differences, React Query cache migration) -**Research flag:** Interface migration is straightforward (same UI, swap data layer) but the JoyId wallet connector behavior difference between Lumos and CCC needs manual verification with actual wallet hardware. - -### Phase 4: Ecosystem Hardening -**Rationale:** After the library is stable and published, long-term ecosystem work becomes safe to pursue without destabilizing production. -**Delivers:** CCC Udt investigation conclusions; potential upstream CCC contributions; type export completeness; improved test coverage. -**Addresses:** D-2 (CCC Udt investigation), D-9 (upstream contributions), TS-12 (type audit if deferred) -**Avoids:** Pitfall 2 (CCC Udt subclassing for multi-representation value) — this is where the subclassing viability is confirmed or the fallback approach is chosen -**Research flag:** D-2 (CCC Udt subclassing investigation) is explicitly exploratory — findings may change the long-term architecture of `IckbUdt`. Schedule this after Phase 2 validation so the decision is informed by production experience. - -### Phase Ordering Rationale - -- **Test infrastructure before code changes:** The pitfalls research is unambiguous — characterization tests and codec roundtrip tests must exist before removing SmartTransaction. Adding them after is too late. -- **Library before apps:** The feature dependency graph is strict: TS-1 → TS-5 → TS-6/TS-7 → TS-4. Any deviation risks app migration targeting an unstable API. -- **Bot before interface:** Bot validates correctness under real conditions. Interface migration is lower risk but depends on knowing the library is correct. -- **Lumos removal last:** The legacy packages must remain functional until every consumer is migrated. Early removal blocks incremental progress. -- **Udt investigation deferred:** D-2 is exploratory and should not block production library work. Its findings are architecture inputs for future decisions, not requirements for v1. - -### Research Flags - -Needs deeper research during planning: -- **Phase 1d (IckbUdt subclassing):** **Resolved in Phase 3 research.** `infoFrom()` is the preferred override point — input cells have `outPoint` for header fetching, `CellAny` has `capacityFree`. See 03-RESEARCH.md. -- **Phase 3 (JoyId wallet connector):** Manual testing with actual JoyId hardware required; CCC's wallet connector API differs from Lumos in ways that affect UX flow. - -Standard patterns (skip research-phase): -- **Phase 1b/1c (utils, dao, order refactor):** Mapping of SmartTransaction methods to CCC equivalents is fully documented in STACK.md. Straight mechanical migration with test coverage. -- **Phase 2 (bot migration):** Pattern is migration from Lumos primitives to CCC + new packages. Well-documented by existing code and the explicit completion pipeline. -- **Phase 4 (npm publication):** Already configured (changesets, provenance). Execution only. - -## Confidence Assessment - -| Area | Confidence | Notes | -|------|------------|-------| -| Stack | HIGH | Primary source is local CCC source code (`forks/ccc/`); all APIs verified by direct inspection | -| Features | HIGH | Based on direct codebase analysis + CCC docs + npm ecosystem survey; competitor analysis confirms iCKB has no direct competitors | -| Architecture | HIGH | Build order derived from package dependency graph; key patterns verified against CCC Udt source; override point resolved (`infoFrom`, not `getInputsInfo`/`getOutputsInfo` — see Phase 3 research) | -| Pitfalls | HIGH | Derived from direct code reading (SmartTransaction 517 lines, IckbUdtManager 213 lines, CCC Udt 1798 lines) and on-chain contract constraints | - -**Overall confidence:** HIGH - -### Gaps to Address - -- **Resolved — CCC Udt override point:** Phase 3 research (03-RESEARCH.md) determined that `infoFrom()` is the optimal override point. The earlier recommendation to override `getInputsInfo()`/`getOutputsInfo()` was based on the incorrect premise that `CellAnyLike` lacks `outPoint` — it actually has `outPoint?: OutPointLike | null`, and input cells from `getInputsInfo()` → `CellInput.getCell()` always have `outPoint` set. `CellAny` also has `capacityFree`. See 03-RESEARCH.md for the corrected design. -- **Resolved — DAO profit in CCC `getInputsCapacity`:** Verified from CCC source (transaction.ts lines 1860-1883) that `Transaction.getInputsCapacity()` handles DAO profit natively via `getInputsCapacityExtra()` → `CellInput.getExtraCapacity()` → `Cell.getDaoProfit()`. No standalone utility needed. SmartTransaction's override of `getInputsCapacity()` can be dropped without replacement. -- **Resolved — CCC PR #328 (FeePayer):** PR #328 is now integrated into `forks/ccc` via pins. FeePayer classes are available at `forks/ccc/packages/core/src/signer/feePayer/`. User decision during Phase 3 context: design around PR #328 as target architecture. -- **Bot key logging security:** PITFALLS.md notes the faucet already has a private key logging bug. The bot migration must include an explicit security audit of all logging paths. - -## Sources - -### Primary (HIGH confidence) -- `forks/ccc/packages/udt/src/udt/index.ts` — CCC Udt class (1798 lines), complete UDT lifecycle API -- `forks/ccc/packages/core/src/ckb/transaction.ts` — CCC Transaction class (2537 lines), completeFee/completeInputsByCapacity/getInputsCapacity -- `forks/ccc/packages/core/src/client/client.ts` — CCC Client with cache, findCells, cell/header fetching -- `packages/utils/src/transaction.ts` — SmartTransaction (deleted in Phase 1), was source of truth for replacement requirements -- `packages/utils/src/udt.ts` — Current UdtManager/UdtHandler (393 lines) -- `packages/core/src/udt.ts` — Current IckbUdtManager (213 lines), triple-representation balance logic -- `forks/contracts/schemas/encoding.mol` — Molecule schema, byte layout ground truth -- `forks/contracts/scripts/contracts/ickb_logic/src/entry.rs` — On-chain conservation law and exchange rate -- `.planning/PROJECT.md` — Project requirements and constraints - -### Secondary (MEDIUM confidence) -- CCC GitHub: [ckb-devrel/ccc](https://github.com/ckb-devrel/ccc) — ecosystem context, PR #328 status -- CCC docs: [docs.ckbccc.com](https://docs.ckbccc.com/) — API surface documentation -- @ickb/utils on npm: [npmjs.com/@ickb/utils](https://www.npmjs.com/package/@ickb/utils) — current published versions - -### Tertiary (LOW confidence) -- Enhanced UDT Standard discussion: [Nervos Talk](https://talk.nervos.org/t/enhanced-udt-standard/8354) — ecosystem context only - ---- -*Research completed: 2026-02-21* -*Ready for roadmap: yes* diff --git a/.pnpmfile.cjs b/.pnpmfile.cjs deleted file mode 100644 index 716c34b..0000000 --- a/.pnpmfile.cjs +++ /dev/null @@ -1,167 +0,0 @@ -// .pnpmfile.cjs — Two jobs: -// -// 1. Auto-replay: bootstrap forker tool, then clone + patch managed forks on -// first `pnpm install` (if pins exist). Reference-only entries (no pins, -// empty refs) are shallow-cloned. replay.sh handles git clone, merge replay, -// lockfile removal, and source patching (jq exports rewrite). It does NOT -// run pnpm install internally — the root workspace install handles fork deps -// alongside everything else. -// -// 2. readPackage hook: rewrite fork deps from catalog ranges to workspace:*. -// Fork packages live in pnpm-workspace.yaml, so you'd expect pnpm to link -// them automatically. It doesn't — catalog: specifiers resolve to a semver -// range (e.g. ^1.12.2) BEFORE workspace linking is considered, so pnpm -// fetches from the registry even with link-workspace-packages = true. -// This hook intercepts every package.json at resolution time and forces -// workspace:* for any dep whose name matches a local fork package. -// When no forks are cloned, the hook is a no-op, so catalog ranges fall -// through to the registry normally. - -const { execFileSync } = require("child_process"); -const { existsSync, readdirSync, readFileSync, rmSync } = require("fs"); -const { join } = require("path"); - -const forksDir = join(__dirname, "forks"); -const configPath = join(forksDir, "config.json"); - -// Read unified config -let config = {}; -if (existsSync(configPath)) { - config = JSON.parse(readFileSync(configPath, "utf8")); -} - -// 1. Auto-replay fork pins on first pnpm install -// Skip when record.sh is running — it rebuilds pins from scratch. -const isRecord = process.env.FORKER_RECORDING === "1"; -if (!isRecord) { - // Bootstrap forker tool: if forks/forker/ doesn't exist, clone it - const forkerDir = join(forksDir, "forker"); - if (!existsSync(forkerDir) && config.forker) { - const upstream = config.forker.upstream; - if (upstream) { - try { - execFileSync("git", ["clone", "--depth", "1", upstream, forkerDir], { - cwd: __dirname, - stdio: ["ignore", "pipe", "pipe"], - }); - // Apply any local patches for forker - const forkerPinDir = join(forksDir, ".pin", "forker"); - if (existsSync(forkerPinDir)) { - const patches = readdirSync(forkerPinDir) - .filter((f) => f.startsWith("local-") && f.endsWith(".patch")) - .sort(); - for (const patch of patches) { - execFileSync( - "git", - ["apply", join(forkerPinDir, patch)], - { cwd: forkerDir, stdio: ["ignore", "pipe", "pipe"] }, - ); - } - } - } catch (err) { - // Clean up partial state so next install retries from scratch - try { - rmSync(forkerDir, { recursive: true, force: true }); - } catch {} - process.stderr.write("Bootstrapping forker tool…\n"); - process.stderr.write(err.stdout?.toString() ?? ""); - process.stderr.write(err.stderr?.toString() ?? ""); - throw err; - } - } - } - - // Replay/clone each entry - for (const [name, entry] of Object.entries(config)) { - if (name === "forker") continue; // already handled above - const cloneDir = join(forksDir, name); - const hasPins = existsSync(join(forksDir, ".pin", name, "manifest")); - - if (!existsSync(cloneDir)) { - if (hasPins) { - // Replay from pins using forker - try { - execFileSync( - "bash", - [join(forkerDir, "replay.sh"), name], - { cwd: __dirname, stdio: ["ignore", "pipe", "pipe"] }, - ); - } catch (err) { - process.stderr.write(`Replaying ${name} pins…\n`); - process.stderr.write(err.stdout?.toString() ?? ""); - process.stderr.write(err.stderr?.toString() ?? ""); - throw err; - } - } else if ( - Array.isArray(entry.refs) && - entry.refs.length === 0 && - entry.upstream - ) { - // Reference-only entry: shallow clone - try { - execFileSync( - "git", - ["clone", "--depth", "1", entry.upstream, cloneDir], - { cwd: __dirname, stdio: ["ignore", "pipe", "pipe"] }, - ); - } catch (err) { - process.stderr.write(`Cloning ${name} (reference)…\n`); - process.stderr.write(err.stdout?.toString() ?? ""); - process.stderr.write(err.stderr?.toString() ?? ""); - throw err; - } - } - } - } -} - -// 2. Discover local fork packages and build the override map -const localOverrides = {}; -for (const [name, entry] of Object.entries(config)) { - const cloneDir = join(forksDir, name); - if (!existsSync(cloneDir)) continue; - const includes = entry.workspace?.include ?? []; - const excludes = new Set(entry.workspace?.exclude ?? []); - for (const pattern of includes) { - // Simple glob: only supports trailing /* (e.g. "packages/*") - const base = pattern.replace(/\/\*$/, ""); - const pkgsRoot = join(cloneDir, base); - if (!existsSync(pkgsRoot)) continue; - for (const dir of readdirSync(pkgsRoot, { withFileTypes: true })) { - if (!dir.isDirectory()) continue; - const relPath = `${base}/${dir.name}`; - if (excludes.has(relPath)) continue; - const pkgJsonPath = join(pkgsRoot, dir.name, "package.json"); - if (!existsSync(pkgJsonPath)) continue; - const { name: pkgName } = JSON.parse( - readFileSync(pkgJsonPath, "utf8"), - ); - if (pkgName) { - localOverrides[pkgName] = "workspace:*"; - } - } - } -} - -const hasOverrides = Object.keys(localOverrides).length > 0; - -function readPackage(pkg) { - if (!hasOverrides) return pkg; - - for (const field of [ - "dependencies", - "devDependencies", - "optionalDependencies", - ]) { - if (!pkg[field]) continue; - for (const [name, linkSpec] of Object.entries(localOverrides)) { - if (pkg[field][name]) { - pkg[field][name] = linkSpec; - } - } - } - - return pkg; -} - -module.exports = { hooks: { readPackage } }; diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 38a9792..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,29 +0,0 @@ -# AI Coworker Configuration - -## Meta - -- **Learn**: When a non-obvious constraint causes a failure or surprises you, leave a concise note here and a detailed comment at the relevant location -- `CLAUDE.md` is a symlink to this file, created by `pnpm coworker` -- Refer to yourself as "AI Coworker" in docs and comments, not by product or company name -- Never add AI tool attribution or branding to PR descriptions, commit messages, or code comments -- Do not install or use `gh` CLI -- When a post-plan fix changes a documented decision, update the planning docs in the same commit - -## Knowledge - -- **Fork Management**: Before working in `forks/`, read `forks/forker/README.md` for directory structure, pin format, and workflows -- Use `git -C ` to run git commands in fork clones or other repos — never `cd` into them -- Always compare CKB scripts using full `Script.eq()` (codeHash + hashType + args), never just `codeHash`. Partial comparison silently matches wrong scripts - -## PR Workflow - -1. **Routine Pre-PR Validation**: `pnpm check:full`, it wipes derived state and regenerates from scratch. If any fork clone has pending work, the wipe is skipped to prevent data loss — re-record or push fork changes first for a clean validation -2. **Open a PR**: If any package needs a version bump, run `pnpm changeset` first. Push the branch and present a clickable markdown link `[title](url)` where the URL is a GitHub compare URL (`quick_pull=1`). Base branch is `master`. Prefill "title" (concise, under 70 chars) and "body" (markdown with ## Why and ## Changes sections) -3. **Fetch PR review comments**: Use the GitHub REST API via curl. Fetch all three comment types (issue comments, reviews, and inline comments). Categorize feedback by actionability (action required / informational), not by source (human / bot) -4. **Copy to clipboard replies**: - -```sh -head -c -1 <<'EOF' | wl-copy -@account-name content goes here -EOF -``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index ff5813d..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,130 +0,0 @@ -# Contributing to ickb/stack - -First off, thank you for considering contributing to ickb/stack! We appreciate your help in making ickb/stack better. - -## Where do I go from here? - -If you've noticed a bug or have a feature request, we'd appreciate it if you [make one](https://github.com/ickb/stack/issues/new)! It's generally best if you get confirmation of your bug or approval for your feature request this way before starting to code. - -## Guiding Principles - -When contributing to ickb/stack, please keep the following principles in mind. These guidelines are designed to ensure that ickb/stack is not only a powerful tool but also a pleasure to use for developers. - -* **Design for the Majority**: Prioritize the most common use cases. Strive to make these scenarios as intuitive and frictionless as possible. -* **Usability Over Performance**: While performance is important, the ease of use and overall developer experience should always be the primary consideration. A slight performance trade-off is acceptable if it leads to a more intuitive API or a clearer development process. -* **Good Developer Experience is Key**: Code that simply "works" is not enough. Aim to write code that is a joy to work with. This includes clear naming, comprehensive documentation, and a logical, predictable API. A positive developer experience is a feature in itself. - -In summary, our goal is to create a tool that is both powerful and developer-friendly. By focusing on the most common use cases, prioritizing usability, and striving for a great developer experience, we can build a better ickb/stack for everyone. - -### Fork & create a branch - -If you'd like to contribute a fix, you can [fork ickb/stack](https://github.com/ickb/stack/fork) and create a branch with a descriptive name. - -A good branch name would be in the format of `/`, for example: - -```sh -git checkout -b feat/add-new-api -``` - -Or for a bug fix: - -```sh -git checkout -b fix/resolve-memory-leak -``` - -### Get the project running - -To get the project running on your local machine, please run: -```sh -pnpm install -``` - -### Make your changes - -Now you can modify the code to fix the bug or add the feature. - -### Run tests - -Please make sure the tests pass before you commit your changes. - -```sh -pnpm test -``` - -### Lint and format your code - -We use ESLint for linting and Prettier for formatting. Please ensure your code is clean before committing. - -```sh -pnpm lint -pnpm format -``` - -### Commit your changes - -Please add a changeset for your changes. This is how we track changes and generate changelogs. - -```sh -pnpm changeset -``` - -This will ask you a few questions and then generate a file in the `.changeset` directory. Please add this file to your commit. - -### Commit Message Format - -We use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification for our commit messages. This allows for easier automation of changelog generation and versioning. - -Here are a few examples of good commit messages: - -- A commit that fixes a bug: - ``` - fix(parser): handle multi-byte characters - ``` -- A commit that adds a new feature: - ``` - feat(api): add new endpoint for user profiles - ``` -- A commit that includes a breaking change: - ``` - feat(auth)!: remove support for deprecated authentication method - - BREAKING CHANGE: The old authentication method is no longer supported. Please upgrade to the new method. - ``` - -### Push to your fork and submit a pull request - -After pushing your changes to your fork, please submit a pull request to the `master` branch of the `ickb/stack` repository. - -After submitting the pull request, our team will review it. We may suggest some changes or improvements or alternatives. - -### Keep Pull Requests Small and Focused - -We prefer small, atomic pull requests over large ones. This makes them easier to review, test, and merge, which means your contributions can be integrated faster. A good pull request is like a single, logical commit. - -Here are some more detailed tips for keeping your pull requests small and focused: - -* **One PR, One Concern:** Each pull request should address a single, well-defined issue or feature. Avoid mixing bug fixes, new features, and refactoring in the same pull request. For example, if you find a bug while working on a new feature, first create a PR to fix the bug, and then create a separate PR for the feature. - -* **Break Down Large Features:** If you're implementing a complex feature, don't try to do it all in one giant PR. Instead, break it down into smaller, incremental steps. For example, if you're adding a new UI component, you could have separate PRs for: - 1. The basic component structure and styling. - 2. The component's state management. - 3. The component's integration with the rest of the application. - -* **Separate Refactoring from Features/Fixes:** If you need to refactor existing code to implement your change, do it in a separate PR *before* you start working on the feature or fix. This makes it clear what changes are refactoring and what changes are new functionality, making the review process much smoother. For example, if you need to rename a function that your new feature will use, submit a PR with just the rename first. - -* **Keep an Eye on the Diff:** As you work, regularly check the size of your diff (`git diff`). If it's getting too large (e.g., more than a few hundred lines of changes), it's a good sign that you should probably split your work into multiple PRs. - -By following these guidelines, you'll not only make the review process easier for us, but you'll also likely find it easier to manage your own work. - -### Interacting with the Gemini Review Bot - -We use a Gemini-powered bot to help with pull request reviews. Here's how to interact with it: - -* **Read Gemini's review comments:** The bot will often provide useful suggestions for improving your code. Please read its comments carefully. -* **Request a re-review:** After you've updated your pull request based on the feedback, you can ask the bot to review your changes again by leaving a comment with `/gemini review`. - -To help your pull request get accepted, please consider the following: - -- Write tests. -- Follow our existing style. -- Write a good commit message. diff --git a/README.md b/README.md index 3830914..a220561 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,64 @@ # iCKB Stack -iCKB Stack Monorepo: all TS libs, web UI, bot, CLI and shared packages, built on top of [CCC](https://github.com/ckb-devrel/ccc). - -## Status - -This monorepo is developing the **new generation** of iCKB libraries, replacing the deprecated `@ickb/lumos-utils` and `@ickb/v1-core` (which were built on the now-deprecated [Lumos](https://github.com/ckb-js/lumos) framework). - -**New packages** (under `packages/`, built on CCC): - -| Package | Purpose | Status | -| ------------- | -------------------------------------------------------------------------- | ------------------ | -| `@ickb/utils` | Blockchain primitives, transaction helpers, epoch arithmetic, UDT handling | Active development | -| `@ickb/dao` | Nervos DAO abstraction layer | Active development | -| `@ickb/order` | Limit order cell management | Active development | -| `@ickb/core` | iCKB core protocol logic (deposits, receipts, owned owner) | Active development | -| `@ickb/sdk` | High-level SDK composing all packages | Active development | - -**Apps migration status:** - -| App | Purpose | Stack | -| ---------------- | --------------------------- | ---------------------------------- | -| `apps/faucet` | Testnet CKB distribution | **Migrated** to new packages + CCC | -| `apps/sampler` | iCKB exchange rate sampling | **Migrated** to new packages + CCC | -| `apps/bot` | Automated order matching | Legacy (`@ickb/v1-core` + Lumos) | -| `apps/tester` | Order creation simulator | Legacy (`@ickb/v1-core` + Lumos) | -| `apps/interface` | React web UI | Legacy (`@ickb/v1-core` + Lumos) | - -**Key upstream contributions:** UDT and Epoch support were contributed to CCC upstream and have been merged. Some local utilities may overlap with features now available natively in CCC. - -## Dependencies - -```mermaid -graph TD; - B["@ickb/utils"] --> A["@ckb-ccc/core"]; - C["@ickb/dao"] --> A; - C --> B; - D["@ickb/core"] --> A; - D --> B; - D --> C; - E["@ickb/order"] --> A; - E --> B; - F["@ickb/sdk"] --> A; - F --> B; - F --> C; - F --> D; - F --> E; - - click A "https://github.com/ckb-devrel/ccc/tree/master/packages/core" "Go to @ckb-ccc/core" - click B "https://github.com/ickb/stack/tree/master/packages/utils" "Go to @ickb/utils" - click C "https://github.com/ickb/stack/tree/master/packages/dao" "Go to @ickb/dao" - click D "https://github.com/ickb/stack/tree/master/packages/core" "Go to @ickb/core" - click E "https://github.com/ickb/stack/tree/master/packages/order" "Go to @ickb/order" - click F "https://github.com/ickb/stack/tree/master/packages/sdk" "Go to @ickb/sdk" +iCKB Stack is the monorepo for the current TypeScript iCKB libraries and apps built on top of [CCC](https://github.com/ckb-devrel/ccc). + +## Transaction Completion Boundary + +`@ickb/sdk` stops at protocol-specific transaction construction. It returns partial `ccc.Transaction` values and does not finalize iCKB UDT balance, CKB capacity, or fees on behalf of the caller. + +Callers own the final completion pipeline: + +1. Use `getConfig(...).managers.ickbUdt` to finish iCKB UDT completion. +2. Then run CCC-native CKB capacity and fee completion. +3. Only then send the transaction. + +## Local CCC Workflow + +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 ``` -## Develop with Forks +`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`. -When `forks/.pin//manifest` is committed, `pnpm install` automatically sets up the local fork development environment on first run (by replaying pinned merges via `forks/forker/replay.sh`). No manual setup step is needed — just clone and install: +To inspect that current CCC surface without building anything: ```bash -git clone git@github.com:ickb/stack.git && cd stack && pnpm install +pnpm forks:ccc:plan ``` -To redo the setup from scratch: `bash forks/forker/clean-all.sh && pnpm install`. +For machine-readable inspection, use `pnpm -s forks:ccc --json`. + +For active CCC work, keep built output fresh with: -After `pnpm install`, see `forks/forker/README.md` for recording new pins, developing fork PRs, and the full workflow. +```bash +pnpm forks:ccc --watch +``` -## Developer Scripts +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 +``` -| Command | Description | -| -------------------------------- | --------------------------------------------------------------------------------- | -| `pnpm coworker` | Launch an interactive AI Coworker session (full autonomy, opus model). | -| `pnpm coworker:ask` | One-shot AI query for scripting (sonnet model, stateless). Used by record.sh. | -| `bash forks/forker/status.sh ` | Check if fork clone matches pinned state. Exit 0 = safe to wipe. | -| `bash forks/forker/record.sh ` | Record fork pins (clone, merge refs, build). Guarded against pending work. | -| `bash forks/forker/save.sh ` | Capture local fork work as a patch in .pin/ (survives re-records and replays). | -| `bash forks/forker/push.sh ` | Cherry-pick commits from wip branch onto a PR branch for pushing to the fork. | -| `bash forks/forker/clean.sh ` | Remove fork clone, keep pins (guarded). Re-replay on next `pnpm install`. | -| `bash forks/forker/reset.sh ` | Remove fork clone and pins (guarded). Restores published packages. | -| `pnpm check:full` | Wipe derived state and validate from scratch. Skips wipe if forks have pending work.| +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`. -## Epoch Semantic Versioning +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. -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. +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. ## Licensing diff --git a/apps/bot/package.json b/apps/bot/package.json index e3948b0..24b05c0 100644 --- a/apps/bot/package.json +++ b/apps/bot/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "tsgo", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules", @@ -60,4 +60,4 @@ "@ickb/lumos-utils": "1.4.2", "@ickb/v1-core": "1.4.2" } -} \ No newline at end of file +} diff --git a/apps/bot/typedoc.json b/apps/bot/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/apps/bot/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/apps/faucet/package.json b/apps/faucet/package.json index 3c55a2a..85c3679 100644 --- a/apps/faucet/package.json +++ b/apps/faucet/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules", @@ -55,4 +55,4 @@ "@ickb/order": "workspace:*", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/apps/faucet/tsconfig.json b/apps/faucet/tsconfig.json index 80da643..9f29614 100644 --- a/apps/faucet/tsconfig.json +++ b/apps/faucet/tsconfig.json @@ -4,7 +4,8 @@ "noEmit": false, "rootDir": "src", "outDir": "dist", - "sourceRoot": "../src" + "sourceRoot": "../src", + "types": ["node"] }, "include": ["src"], } diff --git a/apps/faucet/typedoc.json b/apps/faucet/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/apps/faucet/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/apps/interface/.prettierrc b/apps/interface/.prettierrc deleted file mode 100644 index 8b0bc4e..0000000 --- a/apps/interface/.prettierrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["prettier-plugin-tailwindcss"] -} \ No newline at end of file diff --git a/apps/interface/package.json b/apps/interface/package.json index 11fef37..e5932e7 100644 --- a/apps/interface/package.json +++ b/apps/interface/package.json @@ -13,7 +13,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "bash ../../tsgo-filter.sh && vite build", + "build": "tsc && vite build", "preview": "vite preview", "lint": "eslint ./src", "clean": "rm -fr dist", @@ -21,27 +21,19 @@ }, "devDependencies": { "@babel/preset-react": "^7.27.1", - "@eslint/js": "^9.38.0", "@tailwindcss/vite": "^4.1.14", "@types/node": "^22.18.11", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", "@vitejs/plugin-basic-ssl": "^1.2.0", "@vitejs/plugin-react": "^4.7.0", - "babel-plugin-react-compiler": "latest", - "eslint": "^9.38.0", - "eslint-plugin-react-compiler": "latest", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.24", - "prettier": "^3.6.2", - "prettier-plugin-tailwindcss": "^0.6.14", + "babel-plugin-react-compiler": "^1.0.0", "tailwindcss": "^4.1.14", "typescript": "^5.9.3", - "typescript-eslint": "^8.46.1", "vite": "^6.4.0" }, "dependencies": { - "@ckb-ccc/ccc": "^1.1.21", + "@ckb-ccc/ccc": "catalog:", "@ckb-lumos/base": "^0.23.0", "@ckb-lumos/codec": "^0.23.0", "@ckb-lumos/common-scripts": "^0.23.0", @@ -55,4 +47,4 @@ "react": "^19.2.0", "react-dom": "^19.2.0" } -} \ No newline at end of file +} diff --git a/apps/interface/src/utils.ts b/apps/interface/src/utils.ts index 1d6f47a..9935b94 100644 --- a/apps/interface/src/utils.ts +++ b/apps/interface/src/utils.ts @@ -115,7 +115,7 @@ export const epochSinceValuePadding = Object.freeze({ number: 0, index: 0, length: 1, -} as EpochSinceValue); +}); export type TxInfo = Readonly<{ tx: TransactionSkeletonType; diff --git a/apps/interface/vite.config.ts b/apps/interface/vite.config.ts index 60457d6..e543e4d 100644 --- a/apps/interface/vite.config.ts +++ b/apps/interface/vite.config.ts @@ -1,50 +1,22 @@ -import { defineConfig } from "vite"; import tailwindcss from "@tailwindcss/vite"; +import basicSsl from "@vitejs/plugin-basic-ssl"; import react from "@vitejs/plugin-react"; -import basicSsl from '@vitejs/plugin-basic-ssl' -import { existsSync, readFileSync } from "fs"; -import { join } from "path"; - -// Detect if any managed fork clones are present (forks/ directory layout) -const root = join(__dirname, "../.."); -const hasForkSource = (() => { - try { - const configPath = join(root, "forks", "config.json"); - if (!existsSync(configPath)) return false; - const config = JSON.parse(readFileSync(configPath, "utf8")); - for (const [name, entry] of Object.entries(config)) { - // Managed forks have non-empty refs; reference-only clones have refs: [] - if (!Array.isArray(entry.refs) || entry.refs.length === 0) continue; - if (existsSync(join(root, "forks", name))) return true; - } - } catch (err) { - console.error("Failed to detect fork sources:", err); - } - return false; -})(); +import { defineConfig } from "vite"; +// Local CCC iteration resolves built output from forks/ccc/repo, so the +// interface no longer needs the old raw-fork-source Babel/shim escape hatches. // https://vitejs.dev/config/ export default defineConfig({ server: { - host: true + host: true, }, plugins: [ tailwindcss(), react({ - // Fork source uses decorators — skip babel, let esbuild handle them - ...(hasForkSource && { exclude: [/forks\/\w+\//] }), babel: { plugins: [["babel-plugin-react-compiler"]], }, }), - basicSsl() + basicSsl(), ], - build: { - rollupOptions: { - // Fork source uses `export { SomeType }` instead of `export type { SomeType }`. - // esbuild strips the type declarations but can't strip value-looking re-exports, - // so rollup sees missing exports. Shimming is safe — they're never used at runtime. - ...(hasForkSource && { shimMissingExports: true }), - }, - }, }); diff --git a/apps/sampler/package.json b/apps/sampler/package.json index 9e5a7cd..f6be753 100644 --- a/apps/sampler/package.json +++ b/apps/sampler/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules", @@ -53,4 +53,4 @@ "@ickb/core": "workspace:*", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/apps/sampler/tsconfig.json b/apps/sampler/tsconfig.json index 80da643..9f29614 100644 --- a/apps/sampler/tsconfig.json +++ b/apps/sampler/tsconfig.json @@ -4,7 +4,8 @@ "noEmit": false, "rootDir": "src", "outDir": "dist", - "sourceRoot": "../src" + "sourceRoot": "../src", + "types": ["node"] }, "include": ["src"], } diff --git a/apps/sampler/typedoc.json b/apps/sampler/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/apps/sampler/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/apps/tester/package.json b/apps/tester/package.json index 01b47bb..17a9d07 100644 --- a/apps/tester/package.json +++ b/apps/tester/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "tsgo", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules", @@ -57,4 +57,4 @@ "@ickb/lumos-utils": "1.4.2", "@ickb/v1-core": "1.4.2" } -} \ No newline at end of file +} diff --git a/apps/tester/typedoc.json b/apps/tester/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/apps/tester/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/forks/.gitignore b/forks/.gitignore index e5bf8b4..3dee754 100644 --- a/forks/.gitignore +++ b/forks/.gitignore @@ -1,5 +1,3 @@ -* -!.gitignore -!config.json -!.pin/ -!.pin/** +*/repo/ +.stage/ +.lock/ diff --git a/forks/.pin/ccc/HEAD b/forks/.pin/ccc/HEAD deleted file mode 100644 index 50d606a..0000000 --- a/forks/.pin/ccc/HEAD +++ /dev/null @@ -1 +0,0 @@ -226271097702bc04dbb1b0d76ee79c2b7bdd6c5e diff --git a/forks/.pin/ccc/manifest b/forks/.pin/ccc/manifest deleted file mode 100644 index 9715847..0000000 --- a/forks/.pin/ccc/manifest +++ /dev/null @@ -1,5 +0,0 @@ -50d657beea36de3ebbd80ee88209842644daef34 master -8e63e3a21f1824445b2c339ffe4927a2a8af1bcf 359 -5761fe63fcb29ac810fab5e71063424692f65592 328 -0e18748fb139d71338c109d71aae5b149cb58af3 releases/next -0ad2a5f6305d4964b00394bc8a6ed50136fdffa8 releases/udt diff --git a/forks/.pin/ccc/res-2.resolution b/forks/.pin/ccc/res-2.resolution deleted file mode 100644 index 711d04e..0000000 --- a/forks/.pin/ccc/res-2.resolution +++ /dev/null @@ -1,15 +0,0 @@ ---- packages/core/src/ckb/transaction.ts -CONFLICT ours=5 base=4 theirs=1 resolution=4 sha=9b7e58e11a803c51911391e089e70989663efb79fe8775ddc4335e5c2202248d -import { - ErrorNervosDaoOutputLimit, - ErrorTransactionInsufficientCoin, -} from "./transactionErrors.js"; -CONFLICT ours=97 base=95 theirs=7 resolution=8 sha=35fcc18a78d1a7d169108f94fda08c9a4d720da6a4c8be68130da8a3a8257de3 - const result = await from.completeFee(this, { - changeFn: change, - feeRate: expectedFeeRate, - filter, - options, - }); - await assertDaoOutputLimit(this, from.client); - return result; diff --git a/forks/.pin/ccc/res-4.resolution b/forks/.pin/ccc/res-4.resolution deleted file mode 100644 index 5ecd1e0..0000000 --- a/forks/.pin/ccc/res-4.resolution +++ /dev/null @@ -1,20 +0,0 @@ ---- packages/core/src/ckb/transactionErrors.ts -CONFLICT ours=13 base=0 theirs=3 resolution=13 sha=fb78be5c37c81b8ddc5817c91bc2399cb8a22a6a36b4615041c16f3ee8baa4a3 -export class ErrorNervosDaoOutputLimit extends Error { - public readonly count: number; - public readonly limit: number; - - constructor(count: number) { - super( - `NervosDAO transaction has ${count} output cells, exceeding the limit of 64`, - ); - this.count = count; - this.limit = 64; - } -} - ---- vitest.config.mts -CONFLICT ours=1 base=1 theirs=1 resolution=1 sha=944a4a3ae09aceaa620bd0783e575d8519671a30ea7db8e975d6cff49d8156d2 - projects: packages, -CONFLICT ours=1 base=1 theirs=1 resolution=1 sha=ac0f08d951dbb8bc8f2fe686d0a5ab8e6d8bb47b2e6bc0ce8d565fa4e44d5b5a - include: packages, diff --git a/forks/.pin/forker/HEAD b/forks/.pin/forker/HEAD deleted file mode 100644 index 89a77f6..0000000 --- a/forks/.pin/forker/HEAD +++ /dev/null @@ -1 +0,0 @@ -981bcbddc25b70cb4a0f72c459d067f89ceb252d diff --git a/forks/.pin/forker/manifest b/forks/.pin/forker/manifest deleted file mode 100644 index 2faa0c9..0000000 --- a/forks/.pin/forker/manifest +++ /dev/null @@ -1 +0,0 @@ -981bcbddc25b70cb4a0f72c459d067f89ceb252d master diff --git a/forks/ccc/pin/HEAD b/forks/ccc/pin/HEAD new file mode 100644 index 0000000..92eed96 --- /dev/null +++ b/forks/ccc/pin/HEAD @@ -0,0 +1 @@ +2fbefe4ccdaf6a173d3bc15e7fd8943c5eb50ab7 diff --git a/forks/ccc/pin/LOCAL_BASE b/forks/ccc/pin/LOCAL_BASE new file mode 100644 index 0000000..92eed96 --- /dev/null +++ b/forks/ccc/pin/LOCAL_BASE @@ -0,0 +1 @@ +2fbefe4ccdaf6a173d3bc15e7fd8943c5eb50ab7 diff --git a/forks/ccc/pin/manifest b/forks/ccc/pin/manifest new file mode 100644 index 0000000..f836c20 --- /dev/null +++ b/forks/ccc/pin/manifest @@ -0,0 +1,5 @@ +0dbd492fee83cfbb2e3a2881d6d4876f8e14769f master +0e17e8f713c678c9d417eec313271e3017ae6a68 359 +5761fe63fcb29ac810fab5e71063424692f65592 328 +6727ffe05f60e6bfb2060a565c19acb0fd0f375e releases/next +0ad2a5f6305d4964b00394bc8a6ed50136fdffa8 releases/udt diff --git a/forks/ccc/pin/res-4.resolution b/forks/ccc/pin/res-4.resolution new file mode 100644 index 0000000..505c62a --- /dev/null +++ b/forks/ccc/pin/res-4.resolution @@ -0,0 +1,5 @@ +--- vitest.config.mts +CONFLICT ours=1 base=1 theirs=1 resolution=1 sha=fcdfad3350820e02562bb811cdd7f0d270c70547e1ac9a61c6b904d450ca9cdd + projects: [...packages, "packages/udt"], +CONFLICT ours=1 base=1 theirs=1 resolution=1 sha=ebf7d961f9311563654bf59e4e3251d6e5057b6d410a6acc419c12bd1c793e26 + include: [...packages, "packages/udt"], diff --git a/forks/config.json b/forks/config.json index fd99a2a..9adebb2 100644 --- a/forks/config.json +++ b/forks/config.json @@ -2,6 +2,8 @@ "ccc": { "upstream": "https://github.com/ckb-devrel/ccc.git", "fork": "git@github.com:phroi/ccc.git", + "mode": "managed", + "base_branch": "master", "refs": [ "359", "328", @@ -22,17 +24,8 @@ ] } }, - "forker": { + "phroi_forker": { "upstream": "https://github.com/phroi/forker.git", - "fork": "git@github.com:phroi/forker.git", - "refs": [] - }, - "contracts": { - "upstream": "https://github.com/ickb/contracts.git", - "refs": [] - }, - "whitepaper": { - "upstream": "https://github.com/ickb/whitepaper.git", - "refs": [] + "mode": "reference" } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 57eeac7..55d9e82 100644 --- a/package.json +++ b/package.json @@ -3,38 +3,33 @@ "scripts": { "build": "pnpm -r --filter !./apps/** --filter '!./forks/**' build", "build:all": "pnpm -r --filter '!./forks/**' build", - "check": "pnpm clean:deep && pnpm install && pnpm lint && pnpm build:all && pnpm test:ci", - "check:fresh": "rm pnpm-lock.yaml && pnpm run check", - "check:ci": "CI=true pnpm run check", - "check:full": "[ -f forks/forker/clean-all.sh ] && bash forks/forker/clean-all.sh; pnpm check:fresh && pnpm check:ci", + "check": "CI=true pnpm check:base", + "check:base": "pnpm clean:deep && pnpm check:ccc-overrides && pnpm forks:bootstrap && pnpm install && pnpm forks:ccc && pnpm forks:ccc:smoke && pnpm lint && pnpm build:all && pnpm test:ci", + "check:ccc-overrides": "node scripts/check-ccc-overrides.mjs", + "check:fresh": "rm -f pnpm-lock.yaml && pnpm check", "test": "vitest", - "test:ci": "vitest run", - "test:cov": "vitest run --coverage", + "test:ci": "vitest run && node --test scripts/*.test.mjs", "lint": "pnpm -r --filter '!./forks/**' lint", - "clean": "rm -fr dist packages/*/dist apps/*/dist forks/*/packages/*/dist", - "clean:deep": "pnpm clean && rm -fr node_modules packages/*/node_modules apps/*/node_modules forks/*/packages/*/node_modules", - "sync:template": "pnpm -r --filter !./apps/interface --filter !./packages/utils --filter !. -c exec 'for f in .npmignore tsconfig.json typedoc.json vitest.config.mts; do cp ../../packages/utils/$f .; done'", - "change": "pnpm changeset", - "version": "pnpm changeset version", - "publish": "pnpm publish -r", - "docs": "typedoc", - "coworker": "ln -sf AGENTS.md CLAUDE.md && claude --model opus --dangerously-skip-permissions", - "coworker:ask": "env -u CLAUDECODE claude --print --model sonnet --no-session-persistence" + "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", + "coworker:ask": "opencode run --pure --agent plan" }, "engines": { "node": ">=24" }, "devDependencies": { - "@anthropic-ai/claude-code": "latest", - "@changesets/changelog-github": "^0.5.2", - "@changesets/cli": "^2.29.8", "@eslint/js": "^9.39.3", - "@typescript/native-preview": "latest", "@vitest/coverage-v8": "3.2.4", "eslint": "^9.39.3", - "prettier": "^3.8.1", - "prettier-plugin-organize-imports": "^4.3.0", - "typedoc": "0.28.7", + "eslint-plugin-react-compiler": "19.1.0-rc.2", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.24", "typescript": "^5.9.3", "typescript-eslint": "^8.56.1", "vitest": "^3.2.4" diff --git a/packages/core/package.json b/packages/core/package.json index 1d5ae7e..2b66e1b 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules" @@ -57,4 +57,4 @@ "@ickb/dao": "workspace:*", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/packages/core/src/logic.ts b/packages/core/src/logic.ts index a8ef205..5118bb0 100644 --- a/packages/core/src/logic.ts +++ b/packages/core/src/logic.ts @@ -1,5 +1,5 @@ import { ccc } from "@ckb-ccc/core"; -import { DaoManager } from "@ickb/dao"; +import { assertDaoOutputLimit, DaoManager } from "@ickb/dao"; import { defaultFindCellsLimit, type ScriptDeps, @@ -101,7 +101,7 @@ export class LogicManager implements ScriptDeps { ReceiptData.encode({ depositQuantity, depositAmount }), ); - await ccc.assertDaoOutputLimit(tx, client); + await assertDaoOutputLimit(tx, client); return tx; } diff --git a/packages/core/src/owned_owner.ts b/packages/core/src/owned_owner.ts index 154c3a3..2ab3ccf 100644 --- a/packages/core/src/owned_owner.ts +++ b/packages/core/src/owned_owner.ts @@ -4,7 +4,7 @@ import { unique, type ScriptDeps, } from "@ickb/utils"; -import { daoCellFrom, DaoManager } from "@ickb/dao"; +import { assertDaoOutputLimit, daoCellFrom, DaoManager } from "@ickb/dao"; import { OwnerData } from "./entities.js"; import { OwnerCell, WithdrawalGroup, type IckbDepositCell } from "./cells.js"; @@ -105,7 +105,7 @@ export class OwnedOwnerManager implements ScriptDeps { ); } - await ccc.assertDaoOutputLimit(tx, client); + await assertDaoOutputLimit(tx, client); return tx; } diff --git a/packages/core/typedoc.json b/packages/core/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/packages/core/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/packages/dao/package.json b/packages/dao/package.json index 8453f59..df17f69 100644 --- a/packages/dao/package.json +++ b/packages/dao/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules" @@ -55,4 +55,4 @@ "@ckb-ccc/core": "catalog:", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/packages/dao/src/dao.ts b/packages/dao/src/dao.ts index d01b9d6..7361caf 100644 --- a/packages/dao/src/dao.ts +++ b/packages/dao/src/dao.ts @@ -6,6 +6,18 @@ import { } from "@ickb/utils"; import { daoCellFrom, type DaoCell } from "./cells.js"; +export async function assertDaoOutputLimit( + txLike: ccc.TransactionLike, + client: ccc.Client, +): Promise { + const tx = ccc.Transaction.from(txLike); + if (await ccc.isDaoOutputLimitExceeded(tx, client)) { + throw new Error( + `NervosDAO transaction has ${String(tx.outputs.length)} output cells, exceeding the limit of 64`, + ); + } +} + /** * Manage NervosDAO functionalities. */ @@ -97,7 +109,7 @@ export class DaoManager implements ScriptDeps { ); } - await ccc.assertDaoOutputLimit(tx, client); + await assertDaoOutputLimit(tx, client); return tx; } @@ -173,7 +185,7 @@ export class DaoManager implements ScriptDeps { ); } - await ccc.assertDaoOutputLimit(tx, client); + await assertDaoOutputLimit(tx, client); return tx; } @@ -248,7 +260,7 @@ export class DaoManager implements ScriptDeps { tx.setWitnessArgsAt(inputIndex, witness); } - await ccc.assertDaoOutputLimit(tx, client); + await assertDaoOutputLimit(tx, client); return tx; } diff --git a/packages/dao/typedoc.json b/packages/dao/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/packages/dao/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/packages/order/package.json b/packages/order/package.json index 4140405..82cfd9f 100644 --- a/packages/order/package.json +++ b/packages/order/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules" @@ -55,4 +55,4 @@ "@ckb-ccc/core": "catalog:", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/packages/order/typedoc.json b/packages/order/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/packages/order/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 8d89fbd..e645e84 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules" @@ -58,4 +58,4 @@ "@ickb/order": "workspace:*", "@ickb/utils": "workspace:*" } -} \ No newline at end of file +} diff --git a/packages/sdk/src/constants.ts b/packages/sdk/src/constants.ts index ff9c522..ee92703 100644 --- a/packages/sdk/src/constants.ts +++ b/packages/sdk/src/constants.ts @@ -17,6 +17,10 @@ import { unique, type ScriptDeps } from "@ickb/utils"; * explicit script dependencies for devnet. * @param bots - An optional array of bot script-like objects to augment the list of known bots. * @returns An object containing the instantiated managers and bots. + * + * @remarks `managers.ickbUdt` stays caller-owned on purpose. `IckbSdk` + * builders return partial transactions, so callers should use `ickbUdt` + * for UDT completion before running CCC-native capacity and fee completion. */ export function getConfig( d: @@ -184,7 +188,6 @@ const ORDER = { /** * Mainnet xUDT code cell OutPoint. - * Source: forks/contracts/scripts/deployment/mainnet/deployment.toml */ const MAINNET_XUDT_CODE = { txHash: @@ -194,7 +197,6 @@ const MAINNET_XUDT_CODE = { /** * Mainnet iCKB Logic code cell OutPoint. - * Source: forks/contracts/scripts/deployment/mainnet/deployment.toml */ const MAINNET_LOGIC_CODE = { txHash: @@ -204,7 +206,6 @@ const MAINNET_LOGIC_CODE = { /** * Testnet xUDT code cell OutPoint. - * Source: forks/contracts/scripts/deployment/testnet/deployment.toml */ const TESTNET_XUDT_CODE = { txHash: @@ -214,7 +215,6 @@ const TESTNET_XUDT_CODE = { /** * Testnet iCKB Logic code cell OutPoint. - * Source: forks/contracts/scripts/deployment/testnet/deployment.toml */ const TESTNET_LOGIC_CODE = { txHash: diff --git a/packages/sdk/src/sdk.test.ts b/packages/sdk/src/sdk.test.ts new file mode 100644 index 0000000..3c5959a --- /dev/null +++ b/packages/sdk/src/sdk.test.ts @@ -0,0 +1,108 @@ +import { ccc } from "@ckb-ccc/core"; +import { Info, Ratio } from "@ickb/order"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { IckbSdk, type SystemState } from "./sdk.js"; + +const ratio = Ratio.from({ ckbScale: 1n, udtScale: 1n }); +const tip = { timestamp: 0n } as ccc.ClientBlockHeader; + +function system(overrides: Partial = {}): SystemState { + return { + feeRate: 1n, + tip, + exchangeRatio: ratio, + orderPool: [], + ckbAvailable: 0n, + ckbMaturing: [], + ...overrides, + }; +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("IckbSdk.estimate", () => { + it("omits maturity below the fee threshold", () => { + const result = IckbSdk.estimate( + false, + { ckbValue: 0n, udtValue: 100000n }, + system({ ckbAvailable: 100000n }), + ); + + expect(result.convertedAmount).toBe(99999n); + expect(result.ckbFee).toBe(1n); + expect(result.maturity).toBeUndefined(); + }); + + it("includes maturity once the fee threshold is met", () => { + vi.spyOn(Date, "now").mockReturnValue(1234); + + const result = IckbSdk.estimate( + false, + { ckbValue: 0n, udtValue: 1000000n }, + system({ ckbAvailable: 1000000n }), + ); + + expect(result.convertedAmount).toBe(999990n); + expect(result.ckbFee).toBe(10n); + expect(result.maturity).toBe(601234n); + }); +}); + +describe("IckbSdk.maturity", () => { + it("returns undefined for dual-ratio orders", () => { + const dualRatio = new Info(ratio, ratio, 1); + + expect( + IckbSdk.maturity( + { info: dualRatio, amounts: { ckbValue: 1n, udtValue: 1n } }, + system(), + ), + ).toBeUndefined(); + }); + + it("returns zero for already fulfilled orders", () => { + expect( + IckbSdk.maturity( + { + info: Info.create(true, ratio), + amounts: { ckbValue: 0n, udtValue: 0n }, + }, + system(), + ), + ).toBe(0n); + }); + + it("returns the baseline maturity when enough CKB is already available", () => { + vi.spyOn(Date, "now").mockReturnValue(1234); + + expect( + IckbSdk.maturity( + { + info: Info.create(false, ratio), + amounts: { ckbValue: 0n, udtValue: 100n }, + }, + system({ ckbAvailable: 100n }), + ), + ).toBe(601234n); + }); + + it("picks the first matching maturing CKB entry", () => { + expect( + IckbSdk.maturity( + { + info: Info.create(false, ratio), + amounts: { ckbValue: 0n, udtValue: 100n }, + }, + system({ + ckbMaturing: [ + { ckbCumulative: 50n, maturity: 1000n }, + { ckbCumulative: 100n, maturity: 2000n }, + { ckbCumulative: 150n, maturity: 3000n }, + ], + }), + ), + ).toBe(2000n); + }); +}); diff --git a/packages/sdk/src/sdk.ts b/packages/sdk/src/sdk.ts index 87d1c09..061fa3e 100644 --- a/packages/sdk/src/sdk.ts +++ b/packages/sdk/src/sdk.ts @@ -24,6 +24,10 @@ import { PoolSnapshot } from "./codec.js"; /** * SDK for managing iCKB operations. + * + * This facade intentionally stops at protocol-specific transaction construction. + * Callers complete iCKB UDT balance first, then CKB capacity and fees, with + * CCC-native APIs before sending the transaction. */ export class IckbSdk { /** @@ -208,7 +212,7 @@ export class IckbSdk { * * The method performs the following operations: * - Creates order cell data using provided amounts and order information. - * - Adds required cell dependencies and UDT handlers to the transaction. + * - Adds the required order cell dependencies to the transaction. * - Appends the order cell to the transaction outputs. * * @param txLike - The transaction to which the order cell is added. @@ -218,7 +222,11 @@ export class IckbSdk { * - ckbValue: The CKB amount (may include an internal surplus). * - udtValue: The UDT amount. * - * @returns A Promise resolving to void. + * @returns A Promise resolving to the updated transaction. + * + * @remarks The returned transaction is not finalized. Callers own the + * completion pipeline: finish iCKB UDT completion first, then CKB + * capacity/fee completion, before sending. */ async request( txLike: ccc.TransactionLike, @@ -247,7 +255,11 @@ export class IckbSdk { * @param options - Optional parameters: * - isFulfilledOnly: If true, only order groups with fully or partially fulfilled orders are processed. * - * @returns void + * @returns The updated transaction. + * + * @remarks The returned transaction is not finalized. Callers own the + * completion pipeline: finish iCKB UDT completion first, then CKB + * capacity/fee completion, before sending. */ collect( txLike: ccc.TransactionLike, diff --git a/packages/sdk/typedoc.json b/packages/sdk/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/packages/sdk/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/packages/utils/package.json b/packages/utils/package.json index b36c6f6..dd1974f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -31,7 +31,7 @@ "scripts": { "test": "vitest", "test:ci": "vitest run", - "build": "bash ../../tsgo-filter.sh", + "build": "tsc", "lint": "eslint ./src", "clean": "rm -fr dist", "clean:deep": "rm -fr dist node_modules" @@ -54,4 +54,4 @@ "dependencies": { "@ckb-ccc/core": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/utils/typedoc.json b/packages/utils/typedoc.json deleted file mode 100644 index 28e3fc5..0000000 --- a/packages/utils/typedoc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./src/index.ts"], - "extends": ["../../typedoc.base.json"], -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 384969f..b52269e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,53 +8,44 @@ catalogs: default: '@types/node': specifier: ^24.8.1 - version: 24.10.13 + version: 24.12.2 -pnpmfileChecksum: sha256-ii1GW6FVR8S6G6xZNLWscHPcjUwHIzgpN53HWAjURI4= +overrides: + '@ckb-ccc/ccc': workspace:* + '@ckb-ccc/core': workspace:* + '@ckb-ccc/udt': workspace:* importers: .: devDependencies: - '@anthropic-ai/claude-code': - specifier: latest - version: 2.1.58 - '@changesets/changelog-github': - specifier: ^0.5.2 - version: 0.5.2 - '@changesets/cli': - specifier: ^2.29.8 - version: 2.29.8(@types/node@24.10.13) '@eslint/js': specifier: ^9.39.3 - version: 9.39.3 - '@typescript/native-preview': - specifier: latest - version: 7.0.0-dev.20260225.1 + version: 9.39.4 '@vitest/coverage-v8': specifier: 3.2.4 - version: 3.2.4(vitest@3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + version: 3.2.4(vitest@3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)) eslint: specifier: ^9.39.3 - version: 9.39.3(jiti@2.6.1) - prettier: - specifier: ^3.8.1 - version: 3.8.1 - prettier-plugin-organize-imports: - specifier: ^4.3.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) - typedoc: - specifier: 0.28.7 - version: 0.28.7(typescript@5.9.3) + version: 9.39.4(jiti@2.6.1) + eslint-plugin-react-compiler: + specifier: 19.1.0-rc.2 + version: 19.1.0-rc.2(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.24 + version: 0.4.26(eslint@9.39.4(jiti@2.6.1)) typescript: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: specifier: ^8.56.1 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) apps/bot: dependencies: @@ -88,13 +79,13 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.10.13 + version: 24.12.2 apps/faucet: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ickb/core': specifier: workspace:* version: link:../../packages/core @@ -110,13 +101,13 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.10.13 + version: 24.12.2 apps/interface: dependencies: '@ckb-ccc/ccc': specifier: workspace:* - version: link:../../forks/ccc/packages/ccc + version: link:../../forks/ccc/repo/packages/ccc '@ckb-lumos/base': specifier: ^0.23.0 version: 0.23.0 @@ -143,29 +134,26 @@ importers: version: 1.4.2 '@tanstack/react-query': specifier: ^5.90.5 - version: 5.90.21(react@19.2.4) + version: 5.100.9(react@19.2.5) immutable: specifier: ^4.3.7 - version: 4.3.7 + version: 4.3.8 react: specifier: ^19.2.0 - version: 19.2.4 + version: 19.2.5 react-dom: specifier: ^19.2.0 - version: 19.2.4(react@19.2.4) + version: 19.2.5(react@19.2.5) devDependencies: '@babel/preset-react': specifier: ^7.27.1 version: 7.28.5(@babel/core@7.29.0) - '@eslint/js': - specifier: ^9.38.0 - version: 9.39.3 '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.2.1(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + version: 4.2.4(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)) '@types/node': specifier: ^22.18.11 - version: 22.19.11 + version: 22.19.17 '@types/react': specifier: ^19.2.2 version: 19.2.14 @@ -174,49 +162,28 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-basic-ssl': specifier: ^1.2.0 - version: 1.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + version: 1.2.0(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)) '@vitejs/plugin-react': specifier: ^4.7.0 - version: 4.7.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + version: 4.7.0(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0)) babel-plugin-react-compiler: - specifier: latest + specifier: ^1.0.0 version: 1.0.0 - eslint: - specifier: ^9.38.0 - version: 9.39.3(jiti@2.6.1) - eslint-plugin-react-compiler: - specifier: latest - version: 19.1.0-rc.2(eslint@9.39.3(jiti@2.6.1)) - eslint-plugin-react-hooks: - specifier: ^5.2.0 - version: 5.2.0(eslint@9.39.3(jiti@2.6.1)) - eslint-plugin-react-refresh: - specifier: ^0.4.24 - version: 0.4.26(eslint@9.39.3(jiti@2.6.1)) - prettier: - specifier: ^3.6.2 - version: 3.8.1 - prettier-plugin-tailwindcss: - specifier: ^0.6.14 - version: 0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3))(prettier@3.8.1) tailwindcss: specifier: ^4.1.14 - version: 4.2.1 + version: 4.2.4 typescript: specifier: ^5.9.3 version: 5.9.3 - typescript-eslint: - specifier: ^8.46.1 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) vite: specifier: ^6.4.0 - version: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0) apps/sampler: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ickb/core': specifier: workspace:* version: link:../../packages/core @@ -226,7 +193,7 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.10.13 + version: 24.12.2 apps/tester: dependencies: @@ -254,9 +221,9 @@ importers: devDependencies: '@types/node': specifier: 'catalog:' - version: 24.10.13 + version: 24.12.2 - forks/ccc/packages/ccc: + forks/ccc/repo/packages/ccc: dependencies: '@ckb-ccc/eip6963': specifier: workspace:* @@ -288,25 +255,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -315,9 +282,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/ckb-ccc: + forks/ccc/repo/packages/ckb-ccc: dependencies: '@ckb-ccc/ccc': specifier: workspace:* @@ -325,25 +292,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -352,9 +319,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/connector: + forks/ccc/repo/packages/connector: dependencies: '@ckb-ccc/ccc': specifier: workspace:* @@ -365,22 +332,22 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -389,9 +356,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/connector-react: + forks/ccc/repo/packages/connector-react: dependencies: '@ckb-ccc/connector': specifier: workspace:* @@ -401,29 +368,29 @@ importers: version: 1.0.8(@types/react@19.2.14) react: specifier: '>=16' - version: 19.2.4 + version: 19.2.5 devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/react': specifier: ^19.2.7 version: 19.2.14 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -432,13 +399,13 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/core: + forks/ccc/repo/packages/core: dependencies: '@joyid/ckb': specifier: ^1.1.2 - version: 1.1.3(typescript@5.9.3)(zod@3.25.76) + version: 1.1.4(typescript@5.9.3)(zod@3.25.76) '@noble/ciphers': specifier: ^0.5.3 version: 0.5.3 @@ -462,14 +429,14 @@ importers: version: 6.16.0 isomorphic-ws: specifier: ^5.0.0 - version: 5.0.0(ws@8.19.0) + version: 5.0.0(ws@8.20.0) ws: specifier: ^8.18.3 - version: 8.19.0 + version: 8.20.0 devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/ws': specifier: ^8.18.1 version: 8.18.1 @@ -478,19 +445,19 @@ importers: version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -499,12 +466,12 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) - forks/ccc/packages/did-ckb: + forks/ccc/repo/packages/did-ckb: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -514,43 +481,43 @@ importers: version: link:../type-id '@ipld/dag-cbor': specifier: ^9.2.5 - version: 9.2.5 + version: 9.2.6 devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/node': specifier: ^24.3.0 - version: 24.10.13 + version: 24.12.2 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) tsdown: specifier: 0.19.0-beta.3 - version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260225.1)(synckit@0.11.12)(typescript@5.9.3) + version: 0.19.0-beta.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(synckit@0.11.12)(typescript@5.9.3) typescript: specifier: ^5.9.2 version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) - forks/ccc/packages/eip6963: + forks/ccc/repo/packages/eip6963: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -558,25 +525,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -585,41 +552,41 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/joy-id: + forks/ccc/repo/packages/joy-id: dependencies: '@ckb-ccc/core': specifier: workspace:* version: link:../core '@joyid/ckb': specifier: ^1.1.2 - version: 1.1.3(typescript@5.9.3)(zod@3.25.76) + version: 1.1.4(typescript@5.9.3)(zod@3.25.76) '@joyid/common': specifier: ^0.2.1 - version: 0.2.1(typescript@5.9.3)(zod@3.25.76) + version: 0.2.2(typescript@5.9.3)(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -628,9 +595,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/lumos-patches: + forks/ccc/repo/packages/lumos-patches: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -652,29 +619,29 @@ importers: version: 0.24.0-next.2 '@joyid/ckb': specifier: ^1.1.2 - version: 1.1.3(typescript@5.9.3)(zod@3.25.76) + version: 1.1.4(typescript@5.9.3)(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -683,9 +650,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/nip07: + forks/ccc/repo/packages/nip07: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -693,25 +660,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -720,9 +687,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/okx: + forks/ccc/repo/packages/okx: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -736,25 +703,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -763,9 +730,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/rei: + forks/ccc/repo/packages/rei: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -773,25 +740,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -800,9 +767,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/shell: + forks/ccc/repo/packages/shell: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -825,25 +792,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -852,44 +819,44 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/spore: + forks/ccc/repo/packages/spore: dependencies: '@ckb-ccc/core': specifier: workspace:* version: link:../core axios: specifier: ^1.11.0 - version: 1.13.5 + version: 1.16.0 devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/node': specifier: ^24.3.0 - version: 24.10.13 + version: 24.12.2 copyfiles: specifier: ^2.4.1 version: 2.4.1 dotenv: specifier: ^17.2.1 - version: 17.3.1 + version: 17.4.2 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -898,12 +865,12 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) - forks/ccc/packages/ssri: + forks/ccc/repo/packages/ssri: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -911,28 +878,28 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/node': specifier: ^24.3.0 - version: 24.10.13 + version: 24.12.2 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -941,9 +908,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/type-id: + forks/ccc/repo/packages/type-id: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -951,39 +918,39 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/node': specifier: ^24.3.0 - version: 24.10.13 + version: 24.12.2 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) tsdown: specifier: 0.19.0-beta.3 - version: 0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260225.1)(synckit@0.11.12)(typescript@5.9.3) + version: 0.19.0-beta.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(synckit@0.11.12)(typescript@5.9.3) typescript: specifier: ^5.9.2 version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + version: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) - forks/ccc/packages/udt: + forks/ccc/repo/packages/udt: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -994,28 +961,28 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 '@types/node': specifier: ^24.3.0 - version: 24.10.13 + version: 24.12.2 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1024,9 +991,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/uni-sat: + forks/ccc/repo/packages/uni-sat: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -1034,25 +1001,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1061,9 +1028,9 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/utxo-global: + forks/ccc/repo/packages/utxo-global: dependencies: '@ckb-ccc/core': specifier: workspace:* @@ -1071,25 +1038,25 @@ importers: devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1098,38 +1065,41 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - forks/ccc/packages/xverse: + forks/ccc/repo/packages/xverse: dependencies: '@ckb-ccc/core': specifier: workspace:* version: link:../core + bitcoinjs-lib: + specifier: ^7.0.0 + version: 7.0.1(typescript@5.9.3) valibot: specifier: ^1.1.0 - version: 1.2.0(typescript@5.9.3) + version: 1.3.1(typescript@5.9.3) devDependencies: '@eslint/js': specifier: ^9.34.0 - version: 9.39.3 + version: 9.39.4 copyfiles: specifier: ^2.4.1 version: 2.4.1 eslint: specifier: ^9.34.0 - version: 9.39.3(jiti@2.6.1) + version: 9.39.4(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + version: 10.1.8(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3) prettier: specifier: ^3.6.2 - version: 3.8.1 + version: 3.8.3 prettier-plugin-organize-imports: specifier: ^4.2.0 - version: 4.3.0(prettier@3.8.1)(typescript@5.9.3) + version: 4.3.0(prettier@3.8.3)(typescript@5.9.3) rimraf: specifier: ^6.0.1 version: 6.1.3 @@ -1138,16 +1108,16 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.41.0 - version: 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + version: 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) packages/core: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ckb-ccc/udt': specifier: workspace:* - version: link:../../forks/ccc/packages/udt + version: link:../../forks/ccc/repo/packages/udt '@ickb/dao': specifier: workspace:* version: link:../dao @@ -1159,7 +1129,7 @@ importers: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ickb/utils': specifier: workspace:* version: link:../utils @@ -1168,7 +1138,7 @@ importers: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ickb/utils': specifier: workspace:* version: link:../utils @@ -1177,7 +1147,7 @@ importers: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core '@ickb/core': specifier: workspace:* version: link:../core @@ -1195,7 +1165,7 @@ importers: dependencies: '@ckb-ccc/core': specifier: workspace:* - version: link:../../forks/ccc/packages/core + version: link:../../forks/ccc/repo/packages/core packages: @@ -1206,17 +1176,12 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@anthropic-ai/claude-code@2.1.58': - resolution: {integrity: sha512-NWTMNg6jIVtzUKkYj3qAqHXsD1clgVtKgJGmf1p2IXc5jhP1jOlCezSRvztuDH5omabVfkcrFVIMkZDX+Oe+6g==} - engines: {node: '>=18.0.0'} - hasBin: true - '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} engines: {node: '>=6.9.0'} '@babel/core@7.29.0': @@ -1235,8 +1200,8 @@ packages: resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.6': - resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + '@babel/helper-create-class-features-plugin@7.29.3': + resolution: {integrity: sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -1289,12 +1254,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1353,10 +1318,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -1373,67 +1334,6 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@changesets/apply-release-plan@7.0.14': - resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} - - '@changesets/assemble-release-plan@6.0.9': - resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} - - '@changesets/changelog-git@0.2.1': - resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} - - '@changesets/changelog-github@0.5.2': - resolution: {integrity: sha512-HeGeDl8HaIGj9fQHo/tv5XKQ2SNEi9+9yl1Bss1jttPqeiASRXhfi0A2wv8yFKCp07kR1gpOI5ge6+CWNm1jPw==} - - '@changesets/cli@2.29.8': - resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} - hasBin: true - - '@changesets/config@3.1.2': - resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} - - '@changesets/errors@0.2.0': - resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} - - '@changesets/get-dependents-graph@2.1.3': - resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} - - '@changesets/get-github-info@0.7.0': - resolution: {integrity: sha512-+i67Bmhfj9V4KfDeS1+Tz3iF32btKZB2AAx+cYMqDSRFP7r3/ZdGbjCo+c6qkyViN9ygDuBjzageuPGJtKGe5A==} - - '@changesets/get-release-plan@4.0.14': - resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} - - '@changesets/get-version-range-type@0.4.0': - resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} - - '@changesets/git@3.0.4': - resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} - - '@changesets/logger@0.1.1': - resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} - - '@changesets/parse@0.4.2': - resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} - - '@changesets/pre@2.0.2': - resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} - - '@changesets/read@0.6.6': - resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} - - '@changesets/should-skip-package@0.1.2': - resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} - - '@changesets/types@4.1.0': - resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - - '@changesets/types@6.1.0': - resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} - - '@changesets/write@0.4.0': - resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@ckb-lumos/base@0.23.0': resolution: {integrity: sha512-8aLFsUyWIK0rT7GQlYFuXyiG5lQ2bLRK2GvUsxv5G7I3nJ1UyxjwvVOdtlsR/cwhzOam3ujwqASqBIayBL6GLA==} engines: {node: '>=12.0.0'} @@ -1514,14 +1414,14 @@ packages: resolution: {integrity: sha512-faqOZpj0H21vsqfQXfzRRQUEgF3vZ9i3PcqyF7hNbrNeR6VUcIzJL8QskhjFhBusxAvKf56QbX0/T06/PAgbfg==} engines: {node: '>=12.0.0'} - '@emnapi/core@1.8.1': - resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.8.1': - resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} @@ -1689,8 +1589,8 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/config-helpers@0.4.2': @@ -1701,12 +1601,12 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.4': - resolution: {integrity: sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.3': - resolution: {integrity: sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==} + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -1717,15 +1617,16 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@gerrit0/mini-shiki@3.22.0': - resolution: {integrity: sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -1744,131 +1645,23 @@ packages: resolution: {integrity: sha512-39UKHX2DnCO9fWvM2nqLnDHLzHFSNuaWmTnNfc8Tg4/XD/1iNhafKsqcQXtExcHXji5iUPtAbGWqA4H8beIlhw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@inquirer/external-editor@1.0.3': - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@ipld/dag-cbor@9.2.5': - resolution: {integrity: sha512-84wSr4jv30biui7endhobYhXBQzQE4c/wdoWlFrKcfiwH+ofaPg8fwsM8okX9cOzkkrsAsNdDyH3ou+kiLquwQ==} + '@ipld/dag-cbor@9.2.6': + resolution: {integrity: sha512-vZGJ84Em2jCVAS7td5gc08YTVN8/s4bTQxg4pU77PAXDAR/yLYOthOvkCu01fdl1lrZwz47RdUterxdkrs3p5A==} engines: {node: '>=16.0.0', npm: '>=7.0.0'} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} engines: {node: '>=8'} - '@joyid/ckb@1.1.3': - resolution: {integrity: sha512-zDgrvtpLN2/kEfDDMNSoRfBt0T+R2aUu0FMmIGZYUGw/wIRc9tYSqid5Qa799s9O1/0Er9A7h+1Ckyc8LnbyDA==} + '@joyid/ckb@1.1.4': + resolution: {integrity: sha512-8WqcfFd/kfttuaIf2/XsRcmQkEwYLUnZc9UZRcGSVX6GkwzpOLVY5S6Hq+fDXY82lQo9upJGjjudrtcPKYPx3g==} - '@joyid/common@0.2.1': - resolution: {integrity: sha512-DjA+Cy0koTCmPzhkhHkPc0icRLE78ktZY46rXHXfkSqxwQIJ/ED/whPoeF5tkTrN+teIC/hfzVRVkEE4zh/ASQ==} + '@joyid/common@0.2.2': + resolution: {integrity: sha512-Sh9cBlbL+WgcKJ7jngELg5oY0qAO1trHm4iq1Ao0drWwi4biF8p3cb5mAEoO36UxXOy3CYSDbECWLGIP9lWNgg==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1897,14 +1690,11 @@ packages: '@lit/reactive-element@2.1.2': resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} - '@manypkg/find-root@1.1.0': - resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - - '@manypkg/get-packages@1.1.3': - resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 '@nervosnetwork/ckb-sdk-utils@0.109.5': resolution: {integrity: sha512-Tx642hcJWbN8W3KzCIhIo49yzJ8LMqWopQCSBDKuRmwHesO/bvJqYojCVwfrOyROtFOPhgjyiGm5RXBuxm0KpQ==} @@ -1930,23 +1720,11 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - '@oxc-project/types@0.106.0': resolution: {integrity: sha512-QdsH3rZq480VnOHSHgPYOhjL8O8LBdcnSjM408BpPCCUc0JYYZPG9Gafl9i3OcGk/7137o+gweb4cCv3WAUykg==} - '@oxc-project/types@0.112.0': - resolution: {integrity: sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==} + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -1965,8 +1743,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.0-rc.3': - resolution: {integrity: sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -1977,8 +1755,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.0-rc.3': - resolution: {integrity: sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -1989,8 +1767,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.3': - resolution: {integrity: sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.17': + resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -2001,8 +1779,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-rc.3': - resolution: {integrity: sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -2013,8 +1791,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': - resolution: {integrity: sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -2026,8 +1804,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': - resolution: {integrity: sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -2040,13 +1818,27 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': - resolution: {integrity: sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': resolution: {integrity: sha512-urzJX0HrXxIh0FfxwWRjfPCMeInU9qsImLQxHBgLp5ivji1EEUnOfux8KxPPnRQthJyneBrN2LeqUix9DYrNaQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2054,8 +1846,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': - resolution: {integrity: sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -2068,8 +1860,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': - resolution: {integrity: sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -2081,8 +1873,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': - resolution: {integrity: sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -2092,9 +1884,9 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': - resolution: {integrity: sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': @@ -2103,8 +1895,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': - resolution: {integrity: sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -2115,8 +1907,8 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': - resolution: {integrity: sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -2127,225 +1919,210 @@ packages: '@rolldown/pluginutils@1.0.0-beta.58': resolution: {integrity: sha512-qWhDs6yFGR5xDfdrwiSa3CWGIHxD597uGE/A9xGqytBjANvh4rLCTTkq7szhMV4+Ygh+PMS90KVJ8xWG/TkX4w==} - '@rolldown/pluginutils@1.0.0-rc.3': - resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rolldown/pluginutils@1.0.0-rc.17': + resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + '@rollup/rollup-android-arm-eabi@4.60.2': + resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + '@rollup/rollup-android-arm64@4.60.2': + resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + '@rollup/rollup-darwin-arm64@4.60.2': + resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + '@rollup/rollup-darwin-x64@4.60.2': + resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + '@rollup/rollup-freebsd-arm64@4.60.2': + resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + '@rollup/rollup-freebsd-x64@4.60.2': + resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + '@rollup/rollup-linux-arm64-gnu@4.60.2': + resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + '@rollup/rollup-linux-arm64-musl@4.60.2': + resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + '@rollup/rollup-linux-loong64-gnu@4.60.2': + resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + '@rollup/rollup-linux-loong64-musl@4.60.2': + resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + '@rollup/rollup-linux-ppc64-musl@4.60.2': + resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + '@rollup/rollup-linux-riscv64-musl@4.60.2': + resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + '@rollup/rollup-linux-s390x-gnu@4.60.2': + resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + '@rollup/rollup-linux-x64-gnu@4.60.2': + resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + '@rollup/rollup-linux-x64-musl@4.60.2': + resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + '@rollup/rollup-openbsd-x64@4.60.2': + resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + '@rollup/rollup-openharmony-arm64@4.60.2': + resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + '@rollup/rollup-win32-arm64-msvc@4.60.2': + resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + '@rollup/rollup-win32-ia32-msvc@4.60.2': + resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + '@rollup/rollup-win32-x64-gnu@4.60.2': + resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + '@rollup/rollup-win32-x64-msvc@4.60.2': + resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} cpu: [x64] os: [win32] - '@shikijs/engine-oniguruma@3.23.0': - resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} - - '@shikijs/langs@3.23.0': - resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} - - '@shikijs/themes@3.23.0': - resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + '@tailwindcss/node@4.2.4': + resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} - '@shikijs/types@3.23.0': - resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@tailwindcss/node@4.2.1': - resolution: {integrity: sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==} - - '@tailwindcss/oxide-android-arm64@4.2.1': - resolution: {integrity: sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==} + '@tailwindcss/oxide-android-arm64@4.2.4': + resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.2.1': - resolution: {integrity: sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==} + '@tailwindcss/oxide-darwin-arm64@4.2.4': + resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.2.1': - resolution: {integrity: sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==} + '@tailwindcss/oxide-darwin-x64@4.2.4': + resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.2.1': - resolution: {integrity: sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==} + '@tailwindcss/oxide-freebsd-x64@4.2.4': + resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': - resolution: {integrity: sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': - resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': - resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': - resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.2.1': - resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} engines: {node: '>= 20'} cpu: [x64] os: [linux] libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.2.1': - resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==} + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -2356,32 +2133,32 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': - resolution: {integrity: sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': - resolution: {integrity: sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.2.1': - resolution: {integrity: sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==} + '@tailwindcss/oxide@4.2.4': + resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.2.1': - resolution: {integrity: sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==} + '@tailwindcss/vite@4.2.4': + resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/query-core@5.90.20': - resolution: {integrity: sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==} + '@tanstack/query-core@5.100.9': + resolution: {integrity: sha512-SJSFw1S8+kQ0+knv/XGfrbocWoAlT7vDKsSImtLx3ZPQmEcR46hkDjLSvynSy25N8Ms4tIEini1FuBd5k7IscQ==} - '@tanstack/react-query@5.90.21': - resolution: {integrity: sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==} + '@tanstack/react-query@5.100.9': + resolution: {integrity: sha512-Oa44XkaI3kCNN6ME0KByU3xT3SEUNOMfZpHxL6+wFoTm+OeUFYHKdeYVe0aOXlRDm/f15sgLwEt2HDorIdW8+A==} peerDependencies: react: ^18 || ^19 @@ -2415,9 +2192,6 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2427,17 +2201,14 @@ packages: '@types/lodash@4.17.24': resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - - '@types/node@22.19.11': - resolution: {integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==} + '@types/node@22.19.17': + resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} - '@types/node@24.10.13': - resolution: {integrity: sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==} + '@types/node@24.12.2': + resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} @@ -2450,110 +2221,68 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.59.1': + resolution: {integrity: sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.59.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.59.1': + resolution: {integrity: sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.59.1': + resolution: {integrity: sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.59.1': + resolution: {integrity: sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.59.1': + resolution: {integrity: sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.59.1': + resolution: {integrity: sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + '@typescript-eslint/types@8.59.1': + resolution: {integrity: sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.59.1': + resolution: {integrity: sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.59.1': + resolution: {integrity: sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.59.1': + resolution: {integrity: sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-3qSsqv7FmM4z09wEpEXdhmgMfiJF/OMOZa41AdgMsXTTRpX2/38hDg2KGhi3fc24M2T3MnLPLTqw6HyTOBaV1Q==} - cpu: [arm64] - os: [darwin] - - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-F8ZCCX2UESHcbxvnkd1Dn5PTnOOgpGddFHYgn4usyWRMzNZLPP+YjyGALZe9zdR/D8L0uraND0Haok+TPq8xYg==} - cpu: [x64] - os: [darwin] - - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-Up8Z/QNcwce5C4rWnbLNW5w7lRARdyKZcNbB1NMnaswaGOBdeDmdP0wbVsOgJMoDp6vnun+EkvrSft8hWLLhIg==} - cpu: [arm64] - os: [linux] - - '@typescript/native-preview-linux-arm@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-Iu5rnCmqwGIMUu//BXkl9VQaxAAsqVvFhU4mJoNexNkMxPqVcu9quqYAouY7tN/95WcKzUsPpyRfkThdbNFO/g==} - cpu: [arm] - os: [linux] - - '@typescript/native-preview-linux-x64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-WWjIfHCWlcriempYYc/sPJ3HFt6znNZKp60nvDNih0+wmxNqEfT5Yzu5zAY0awIe7XLelFSY+bolkpzMYVWEIQ==} - cpu: [x64] - os: [linux] - - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-lmfQO+HdmPMk0dtPoNo8dZereTUYNQuapsAI7nFHCP8F25I8eGKKXY2nD1R8W1hp/LmVtske1pqKFNN6IOCt5g==} - cpu: [arm64] - os: [win32] - - '@typescript/native-preview-win32-x64@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-e4eJyzR9ne0XreqYgQNqfX7SNuaePxggnUtVrLERgBv25QKwdQl72GnSXDhdxZHzrb97YwumiXWMQQJj9h8NCg==} - cpu: [x64] - os: [win32] - - '@typescript/native-preview@7.0.0-dev.20260225.1': - resolution: {integrity: sha512-mUf1aON+eZLupLorX4214n4W6uWIz/lvNv81ErzjJylD/GyJPEJkvDLmgIK3bbvLpMwTRWdVJLhpLCah5Qe8iA==} - hasBin: true - '@vitejs/plugin-basic-ssl@1.2.0': resolution: {integrity: sha512-mkQnxTkcldAzIsomk1UuLfAu9n+kpQ3JbHcpCp7d2Oo6ITtji8pHS3QToOWjhPFvNQSnhlkAjmGbhv2QvwO/7Q==} engines: {node: '>=14.21.3'} @@ -2630,12 +2359,8 @@ packages: aes-js@4.0.0-beta.5: resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -2657,16 +2382,9 @@ packages: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2675,17 +2393,17 @@ packages: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} - ast-v8-to-istanbul@0.3.11: - resolution: {integrity: sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==} + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axios@1.13.5: - resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + axios@1.16.0: + resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} - b4a@1.8.0: - resolution: {integrity: sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==} + b4a@1.8.1: + resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} peerDependencies: react-native-b4a: '*' peerDependenciesMeta: @@ -2711,21 +2429,25 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + baseline-browser-mapping@2.10.27: + resolution: {integrity: sha512-zEs/ufmZoUd7WftKpKyXaT6RFxpQ5Qm9xytKRHvJfxFV9DFJkZph9RvJ1LcOUi0Z1ZVijMte65JbILeV+8QQEA==} engines: {node: '>=6.0.0'} hasBin: true bech32@2.0.0: resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} - better-path-resolve@1.0.0: - resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} - engines: {node: '>=4'} + bip174@3.0.0: + resolution: {integrity: sha512-N3vz3rqikLEu0d6yQL8GTrSkpYb35NQKWMR7Hlza0lOj6ZOlvQ3Xr7N9Y+JPebaCVoEUHdBeBSuLxcHr71r+Lw==} + engines: {node: '>=18.0.0'} birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + bitcoinjs-lib@7.0.1: + resolution: {integrity: sha512-vwEmpL5Tpj0I0RBdNkcDMXePoaYSTeKY6mL6/l5esbnTs+jGdPDuLp4NY1hSh6Zk5wSgePygZ4Wx5JJao30Pww==} + engines: {node: '>=18.0.0'} + blake2b-wasm@2.4.0: resolution: {integrity: sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==} @@ -2738,22 +2460,21 @@ packages: bn.js@5.2.3: resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@5.0.3: - resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==} - engines: {node: 18 || 20 || >=22} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -2781,11 +2502,11 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001774: - resolution: {integrity: sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==} + caniuse-lite@1.0.30001791: + resolution: {integrity: sha512-yk0l/YSrOnFZk3UROpDLQD9+kC1l4meK/wed583AXrzoarMGJcbRi2Q4RaUYbKxYAsZ8sWmaSa/DsLmdBeI1vQ==} - cborg@4.5.8: - resolution: {integrity: sha512-6/viltD51JklRhq4L7jC3zgy6gryuG5xfZ3kzpE+PravtyeQLeQmCYLREhQH7pWENg5pY4Yu/XCd6a7dKScVlw==} + cborg@5.1.1: + resolution: {integrity: sha512-BDbSRIp6XrQXkTc7g+DN0RB9RrDPTUfals2ecWUlt3juPLjbAvy/V72mJcXY0Ehu0Dq/3WpNCOCT68HUTbW+lw==} hasBin: true chai@5.3.3: @@ -2796,17 +2517,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chardet@2.1.1: - resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - check-error@2.1.3: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -2847,9 +2561,6 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - dataloader@1.4.0: - resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2869,33 +2580,21 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} - dts-resolver@2.1.3: resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} engines: {node: '>=20.19.0'} @@ -2912,8 +2611,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.302: - resolution: {integrity: sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==} + electron-to-chromium@1.5.349: + resolution: {integrity: sha512-QsWVGyRuY07Aqb234QytTfwd5d9AJlfNIQ5wIOl1L+PZDzI9d9+Fn0FRale/QYlFxt/bUnB0/nLd1jFPGxGK1A==} elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -2928,18 +2627,10 @@ packages: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} - enhanced-resolve@5.19.0: - resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} + enhanced-resolve@5.21.0: + resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} engines: {node: '>=10.13.0'} - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -3025,8 +2716,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.3: - resolution: {integrity: sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==} + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -3039,11 +2730,6 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -3079,28 +2765,18 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - extendable-error@0.1.7: - resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -3114,14 +2790,6 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -3130,11 +2798,11 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -3150,14 +2818,6 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3185,12 +2845,8 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} @@ -3213,10 +2869,6 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3239,8 +2891,8 @@ packages: hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} hermes-estree@0.25.1: @@ -3252,20 +2904,12 @@ packages: hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - hookable@6.0.1: - resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + hookable@6.1.1: + resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - human-id@4.1.3: - resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} - hasBin: true - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -3277,8 +2921,8 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + immutable@4.3.8: + resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -3311,18 +2955,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} - - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - isarray@0.0.1: resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} @@ -3373,10 +3005,6 @@ packages: resolution: {integrity: sha512-S/6Oo7ruxx5k8m4qlMnbpwQdJjRsvvfcIhIk1dA9c5y5GNhYHKYKu9krEK3QgBax6CxJuf4gRL2opgLkdzWIKg==} engines: {node: '>=8.0.0'} - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} - hasBin: true - js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -3406,9 +3034,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -3416,83 +3041,80 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.31.1: - resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.31.1: - resolution: {integrity: sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.31.1: - resolution: {integrity: sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.31.1: - resolution: {integrity: sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.31.1: - resolution: {integrity: sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.31.1: - resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [glibc] - lightningcss-linux-arm64-musl@1.31.1: - resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] libc: [musl] - lightningcss-linux-x64-gnu@1.31.1: - resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [glibc] - lightningcss-linux-x64-musl@1.31.1: - resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] libc: [musl] - lightningcss-win32-arm64-msvc@1.31.1: - resolution: {integrity: sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.31.1: - resolution: {integrity: sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.31.1: - resolution: {integrity: sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - lit-element@4.2.2: resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} @@ -3502,10 +3124,6 @@ packages: lit@3.3.2: resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==} - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -3517,25 +3135,19 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.startcase@4.4.0: - resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lunr@2.3.9: - resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3546,25 +3158,10 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - markdown-it@14.1.1: - resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} - hasBin: true - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -3579,15 +3176,15 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.8: - resolution: {integrity: sha512-reYkDYtj/b19TeqbNZCV4q9t+Yxylf/rYBsLb42SXJatTv4/ylq5lEiAmhA/IToxO7NI2UzNMghHoHuaqDkAjw==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minipass@7.1.3: @@ -3599,10 +3196,6 @@ packages: engines: {node: '>=10'} hasBin: true - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3612,8 +3205,8 @@ packages: nanoassert@2.0.0: resolution: {integrity: sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -3629,8 +3222,8 @@ packages: encoding: optional: true - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-releases@2.0.38: + resolution: {integrity: sha512-3qT/88Y3FbH/Kx4szpQQ4HzUbVrHPKTLVpVocKiLfoYvw9XSGOX2FmD2d6DrXbVYyAQTF2HeF6My8jmzx7/CRw==} noms@0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} @@ -3645,43 +3238,17 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - outdent@0.5.0: - resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - - p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@0.2.11: - resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3706,10 +3273,6 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -3720,20 +3283,12 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.13: + resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -3754,117 +3309,38 @@ packages: vue-tsc: optional: true - prettier-plugin-tailwindcss@0.6.14: - resolution: {integrity: sha512-pi2e/+ZygeIqntN+vC573BcW5Cve8zUB0SSAGxqpB4f96boZF4M3phPVoOFCeypwkpRYdi7+jQ5YJJUwrkGUAg==} - engines: {node: '>=14.21.3'} - peerDependencies: - '@ianvs/prettier-plugin-sort-imports': '*' - '@prettier/plugin-hermes': '*' - '@prettier/plugin-oxc': '*' - '@prettier/plugin-pug': '*' - '@shopify/prettier-plugin-liquid': '*' - '@trivago/prettier-plugin-sort-imports': '*' - '@zackad/prettier-plugin-twig': '*' - prettier: ^3.0 - prettier-plugin-astro: '*' - prettier-plugin-css-order: '*' - prettier-plugin-import-sort: '*' - prettier-plugin-jsdoc: '*' - prettier-plugin-marko: '*' - prettier-plugin-multiline-arrays: '*' - prettier-plugin-organize-attributes: '*' - prettier-plugin-organize-imports: '*' - prettier-plugin-sort-imports: '*' - prettier-plugin-style-order: '*' - prettier-plugin-svelte: '*' - peerDependenciesMeta: - '@ianvs/prettier-plugin-sort-imports': - optional: true - '@prettier/plugin-hermes': - optional: true - '@prettier/plugin-oxc': - optional: true - '@prettier/plugin-pug': - optional: true - '@shopify/prettier-plugin-liquid': - optional: true - '@trivago/prettier-plugin-sort-imports': - optional: true - '@zackad/prettier-plugin-twig': - optional: true - prettier-plugin-astro: - optional: true - prettier-plugin-css-order: - optional: true - prettier-plugin-import-sort: - optional: true - prettier-plugin-jsdoc: - optional: true - prettier-plugin-marko: - optional: true - prettier-plugin-multiline-arrays: - optional: true - prettier-plugin-organize-attributes: - optional: true - prettier-plugin-organize-imports: - optional: true - prettier-plugin-sort-imports: - optional: true - prettier-plugin-style-order: - optional: true - prettier-plugin-svelte: - optional: true - - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} hasBin: true process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - quansync@0.2.11: - resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} - quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} - read-yaml-file@1.1.0: - resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} - engines: {node: '>=6'} - readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -3879,17 +3355,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@6.1.3: resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} engines: {node: 20 || >=22} @@ -3919,25 +3387,19 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.0-rc.3: - resolution: {integrity: sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw==} + rolldown@1.0.0-rc.17: + resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + rollup@4.60.2: + resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -3971,20 +3433,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - spawndamnit@3.0.1: - resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -4009,14 +3461,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4032,17 +3480,13 @@ packages: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} - tailwindcss@4.2.1: - resolution: {integrity: sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==} + tailwindcss@4.2.4: + resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - term-size@2.2.1: - resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} - engines: {node: '>=8'} - test-exclude@7.0.2: resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} engines: {node: '>=18'} @@ -4056,12 +3500,12 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} tinypool@1.1.1: @@ -4076,10 +3520,6 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -4087,8 +3527,8 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -4135,27 +3575,25 @@ packages: resolution: {integrity: sha512-rLjWJzQFOq4xw7MgJrCZ6T1jIOvvYElXT12r+y0CC6u67hegDHaxcPqb2fZHOGlqxugGQPNB1EnTezjBetkwkw==} engines: {node: '>=16'} - typedoc@0.28.7: - resolution: {integrity: sha512-lpz0Oxl6aidFkmS90VQDQjk/Qf2iw0IUvFqirdONBdj7jPSN9mGXhy66BcGNDxx5ZMyKKiBVAREvPEzT6Uxipw==} - engines: {node: '>= 18', pnpm: '>= 10'} - hasBin: true - peerDependencies: - typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x - - typescript-eslint@8.56.1: - resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + typescript-eslint@8.59.1: + resolution: {integrity: sha512-xqDcFVBmlrltH64lklOVp1wYxgJr6LVdg3NamBgH2OOQDLFdTKfIZXF5PfghrnXQKXZGTQs8tr1vL7fJvq8CTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + uint8array-tools@0.0.8: + resolution: {integrity: sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==} + engines: {node: '>=14.0.0'} + + uint8array-tools@0.0.9: + resolution: {integrity: sha512-9vqDWmoSXOoi+K14zNaf6LBV51Q8MayF0/IiQs3GlygIKUYtog603e6virExkjjFosfJUBI4LhbQK1iq8IG11A==} + engines: {node: '>=14.0.0'} unconfig-core@7.5.0: resolution: {integrity: sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==} @@ -4172,12 +3610,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - unrun@0.2.27: - resolution: {integrity: sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw==} + unrun@0.2.37: + resolution: {integrity: sha512-AA7vDuYsgeSYVzJMm16UKA+aXFKhy7nFqW9z5l7q44K4ppFWZAMqYS58ePRZbugMLPH0fwwMzD5A8nP0avxwZQ==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -4204,23 +3638,27 @@ packages: uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - valibot@1.2.0: - resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + valibot@1.3.1: + resolution: {integrity: sha512-sfdRir/QFM0JaF22hqTroPc5xy4DimuGQVKFrzF1YfGwaS1nJot3Y8VqMdLO2Lg27fMzat2yD3pY5PbAYO39Gg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: typescript: optional: true + varuint-bitcoin@2.0.0: + resolution: {integrity: sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@6.4.1: - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} + vite@6.4.2: + resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -4330,8 +3768,8 @@ packages: utf-8-validate: optional: true - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -4353,11 +3791,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - yargs-parser@20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} @@ -4388,25 +3821,13 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@anthropic-ai/claude-code@2.1.58': - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 - '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.0': {} + '@babel/compat-data@7.29.3': {} '@babel/core@7.29.0': dependencies: @@ -4414,8 +3835,8 @@ snapshots: '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 @@ -4430,7 +3851,7 @@ snapshots: '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 @@ -4442,13 +3863,13 @@ snapshots: '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.29.0 + '@babel/compat-data': 7.29.3 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 @@ -4514,19 +3935,19 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.6': + '@babel/helpers@7.29.2': dependencies: '@babel/template': 7.28.6 '@babel/types': 7.29.0 - '@babel/parser@7.29.0': + '@babel/parser@7.29.3': dependencies: '@babel/types': 7.29.0 '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color @@ -4587,12 +4008,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.6': {} - '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@babel/traverse@7.29.0': @@ -4600,7 +4019,7 @@ snapshots: '@babel/code-frame': 7.29.0 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/types': 7.29.0 debug: 4.4.3 @@ -4614,165 +4033,6 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@changesets/apply-release-plan@7.0.14': - dependencies: - '@changesets/config': 3.1.2 - '@changesets/get-version-range-type': 0.4.0 - '@changesets/git': 3.0.4 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.8.8 - resolve-from: 5.0.0 - semver: 7.7.4 - - '@changesets/assemble-release-plan@6.0.9': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - semver: 7.7.4 - - '@changesets/changelog-git@0.2.1': - dependencies: - '@changesets/types': 6.1.0 - - '@changesets/changelog-github@0.5.2': - dependencies: - '@changesets/get-github-info': 0.7.0 - '@changesets/types': 6.1.0 - dotenv: 8.6.0 - transitivePeerDependencies: - - encoding - - '@changesets/cli@2.29.8(@types/node@24.10.13)': - dependencies: - '@changesets/apply-release-plan': 7.0.14 - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/changelog-git': 0.2.1 - '@changesets/config': 3.1.2 - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/get-release-plan': 4.0.14 - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.6 - '@changesets/should-skip-package': 0.1.2 - '@changesets/types': 6.1.0 - '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@24.10.13) - '@manypkg/get-packages': 1.1.3 - ansi-colors: 4.1.3 - ci-info: 3.9.0 - enquirer: 2.4.1 - fs-extra: 7.0.1 - mri: 1.2.0 - p-limit: 2.3.0 - package-manager-detector: 0.2.11 - picocolors: 1.1.1 - resolve-from: 5.0.0 - semver: 7.7.4 - spawndamnit: 3.0.1 - term-size: 2.2.1 - transitivePeerDependencies: - - '@types/node' - - '@changesets/config@3.1.2': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/get-dependents-graph': 2.1.3 - '@changesets/logger': 0.1.1 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.8 - - '@changesets/errors@0.2.0': - dependencies: - extendable-error: 0.1.7 - - '@changesets/get-dependents-graph@2.1.3': - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - picocolors: 1.1.1 - semver: 7.7.4 - - '@changesets/get-github-info@0.7.0': - dependencies: - dataloader: 1.4.0 - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - '@changesets/get-release-plan@4.0.14': - dependencies: - '@changesets/assemble-release-plan': 6.0.9 - '@changesets/config': 3.1.2 - '@changesets/pre': 2.0.2 - '@changesets/read': 0.6.6 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/get-version-range-type@0.4.0': {} - - '@changesets/git@3.0.4': - dependencies: - '@changesets/errors': 0.2.0 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.8 - spawndamnit: 3.0.1 - - '@changesets/logger@0.1.1': - dependencies: - picocolors: 1.1.1 - - '@changesets/parse@0.4.2': - dependencies: - '@changesets/types': 6.1.0 - js-yaml: 4.1.1 - - '@changesets/pre@2.0.2': - dependencies: - '@changesets/errors': 0.2.0 - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - - '@changesets/read@0.6.6': - dependencies: - '@changesets/git': 3.0.4 - '@changesets/logger': 0.1.1 - '@changesets/parse': 0.4.2 - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - p-filter: 2.1.0 - picocolors: 1.1.1 - - '@changesets/should-skip-package@0.1.2': - dependencies: - '@changesets/types': 6.1.0 - '@manypkg/get-packages': 1.1.3 - - '@changesets/types@4.1.0': {} - - '@changesets/types@6.1.0': {} - - '@changesets/write@0.4.0': - dependencies: - '@changesets/types': 6.1.0 - fs-extra: 7.0.1 - human-id: 4.1.3 - prettier: 2.8.8 - '@ckb-lumos/base@0.23.0': dependencies: '@ckb-lumos/bi': 0.23.0 @@ -4838,7 +4098,7 @@ snapshots: '@ckb-lumos/toolkit': 0.23.0 bech32: 2.0.0 bs58: 5.0.0 - immutable: 4.3.7 + immutable: 4.3.8 transitivePeerDependencies: - encoding - react-native-b4a @@ -4855,7 +4115,7 @@ snapshots: '@ckb-lumos/toolkit': 0.24.0-next.2 bech32: 2.0.0 bs58: 5.0.0 - immutable: 4.3.7 + immutable: 4.3.8 transitivePeerDependencies: - encoding - react-native-b4a @@ -4909,7 +4169,7 @@ snapshots: '@ckb-lumos/config-manager': 0.23.0 '@ckb-lumos/toolkit': 0.23.0 bech32: 2.0.0 - immutable: 4.3.7 + immutable: 4.3.8 transitivePeerDependencies: - encoding - react-native-b4a @@ -4922,7 +4182,7 @@ snapshots: '@ckb-lumos/config-manager': 0.24.0-next.2 '@ckb-lumos/toolkit': 0.24.0-next.2 bech32: 2.0.0 - immutable: 4.3.7 + immutable: 4.3.8 transitivePeerDependencies: - encoding - react-native-b4a @@ -4966,18 +4226,18 @@ snapshots: dependencies: '@ckb-lumos/bi': 0.24.0-next.2 - '@emnapi/core@1.8.1': + '@emnapi/core@1.10.0': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.8.1': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.1.0': + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 optional: true @@ -5060,14 +4320,14 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.3(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.6.1))': dependencies: - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 @@ -5083,9 +4343,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.4': + '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.14.0 + ajv: 6.15.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 @@ -5097,7 +4357,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.39.3': {} + '@eslint/js@9.39.4': {} '@eslint/object-schema@2.1.7': {} @@ -5106,21 +4366,18 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@gerrit0/mini-shiki@3.22.0': + '@humanfs/core@0.19.2': dependencies: - '@shikijs/engine-oniguruma': 3.23.0 - '@shikijs/langs': 3.23.0 - '@shikijs/themes': 3.23.0 - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 + '@humanfs/types': 0.15.0 - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -5135,7 +4392,7 @@ snapshots: '@ckb-lumos/helpers': 0.23.0 '@ckb-lumos/light-client': 0.23.0 '@ckb-lumos/rpc': 0.23.0 - immutable: 4.3.7 + immutable: 4.3.8 transitivePeerDependencies: - encoding - react-native-b4a @@ -5154,94 +4411,25 @@ snapshots: - encoding - react-native-b4a - '@img/sharp-darwin-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 - optional: true - - '@img/sharp-darwin-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - optional: true - - '@img/sharp-linux-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 - optional: true - - '@img/sharp-linux-arm@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 - optional: true - - '@img/sharp-linux-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - optional: true - - '@img/sharp-win32-arm64@0.34.5': - optional: true - - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@inquirer/external-editor@1.0.3(@types/node@24.10.13)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 24.10.13 - - '@ipld/dag-cbor@9.2.5': + '@ipld/dag-cbor@9.2.6': dependencies: - cborg: 4.5.8 + cborg: 5.1.1 multiformats: 13.4.2 '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.6': {} - '@joyid/ckb@1.1.3(typescript@5.9.3)(zod@3.25.76)': + '@joyid/ckb@1.1.4(typescript@5.9.3)(zod@3.25.76)': dependencies: - '@joyid/common': 0.2.1(typescript@5.9.3)(zod@3.25.76) + '@joyid/common': 0.2.2(typescript@5.9.3)(zod@3.25.76) '@nervosnetwork/ckb-sdk-utils': 0.109.5 cross-fetch: 4.0.0 uncrypto: 0.1.3 @@ -5250,7 +4438,7 @@ snapshots: - typescript - zod - '@joyid/common@0.2.1(typescript@5.9.3)(zod@3.25.76)': + '@joyid/common@0.2.2(typescript@5.9.3)(zod@3.25.76)': dependencies: abitype: 0.8.7(typescript@5.9.3)(zod@3.25.76) type-fest: 4.6.0 @@ -5287,26 +4475,10 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.5.1 - '@manypkg/find-root@1.1.0': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@babel/runtime': 7.28.6 - '@types/node': 12.20.55 - find-up: 4.1.0 - fs-extra: 8.1.0 - - '@manypkg/get-packages@1.1.3': - dependencies: - '@babel/runtime': 7.28.6 - '@changesets/types': 4.1.0 - '@manypkg/find-root': 1.1.0 - fs-extra: 8.1.0 - globby: 11.1.0 - read-yaml-file: 1.1.0 - - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 '@tybys/wasm-util': 0.10.1 optional: true @@ -5334,21 +4506,9 @@ snapshots: '@noble/hashes@1.8.0': {} - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - '@oxc-project/types@0.106.0': {} - '@oxc-project/types@0.112.0': {} + '@oxc-project/types@0.127.0': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -5362,260 +4522,251 @@ snapshots: '@rolldown/binding-android-arm64@1.0.0-beta.58': optional: true - '@rolldown/binding-android-arm64@1.0.0-rc.3': + '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-arm64@1.0.0-beta.58': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.3': + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true '@rolldown/binding-darwin-x64@1.0.0-beta.58': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.3': + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true '@rolldown/binding-freebsd-x64@1.0.0-beta.58': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.3': + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.58': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.58': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-beta.58': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-beta.58': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-beta.58': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-beta.58': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.58': + '@rolldown/binding-wasm32-wasi@1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.58': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true '@rolldown/binding-win32-x64-msvc@1.0.0-beta.58': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true '@rolldown/pluginutils@1.0.0-beta.27': {} '@rolldown/pluginutils@1.0.0-beta.58': {} - '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rolldown/pluginutils@1.0.0-rc.17': {} - '@rollup/rollup-android-arm-eabi@4.59.0': + '@rollup/rollup-android-arm-eabi@4.60.2': optional: true - '@rollup/rollup-android-arm64@4.59.0': + '@rollup/rollup-android-arm64@4.60.2': optional: true - '@rollup/rollup-darwin-arm64@4.59.0': + '@rollup/rollup-darwin-arm64@4.60.2': optional: true - '@rollup/rollup-darwin-x64@4.59.0': + '@rollup/rollup-darwin-x64@4.60.2': optional: true - '@rollup/rollup-freebsd-arm64@4.59.0': + '@rollup/rollup-freebsd-arm64@4.60.2': optional: true - '@rollup/rollup-freebsd-x64@4.59.0': + '@rollup/rollup-freebsd-x64@4.60.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.59.0': + '@rollup/rollup-linux-arm-musleabihf@4.60.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.59.0': + '@rollup/rollup-linux-arm64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.59.0': + '@rollup/rollup-linux-arm64-musl@4.60.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.59.0': + '@rollup/rollup-linux-loong64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.59.0': + '@rollup/rollup-linux-loong64-musl@4.60.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.59.0': + '@rollup/rollup-linux-ppc64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.59.0': + '@rollup/rollup-linux-ppc64-musl@4.60.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.59.0': + '@rollup/rollup-linux-riscv64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.59.0': + '@rollup/rollup-linux-riscv64-musl@4.60.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.59.0': + '@rollup/rollup-linux-s390x-gnu@4.60.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.59.0': + '@rollup/rollup-linux-x64-gnu@4.60.2': optional: true - '@rollup/rollup-linux-x64-musl@4.59.0': + '@rollup/rollup-linux-x64-musl@4.60.2': optional: true - '@rollup/rollup-openbsd-x64@4.59.0': + '@rollup/rollup-openbsd-x64@4.60.2': optional: true - '@rollup/rollup-openharmony-arm64@4.59.0': + '@rollup/rollup-openharmony-arm64@4.60.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.59.0': + '@rollup/rollup-win32-arm64-msvc@4.60.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.59.0': + '@rollup/rollup-win32-ia32-msvc@4.60.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.59.0': + '@rollup/rollup-win32-x64-gnu@4.60.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.59.0': + '@rollup/rollup-win32-x64-msvc@4.60.2': optional: true - '@shikijs/engine-oniguruma@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/themes@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/types@3.23.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vscode-textmate@10.0.2': {} - - '@tailwindcss/node@4.2.1': + '@tailwindcss/node@4.2.4': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.19.0 + enhanced-resolve: 5.21.0 jiti: 2.6.1 - lightningcss: 1.31.1 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.1 + tailwindcss: 4.2.4 - '@tailwindcss/oxide-android-arm64@4.2.1': + '@tailwindcss/oxide-android-arm64@4.2.4': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.1': + '@tailwindcss/oxide-darwin-arm64@4.2.4': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.1': + '@tailwindcss/oxide-darwin-x64@4.2.4': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.1': + '@tailwindcss/oxide-freebsd-x64@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.1': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.2.1': + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.2.1': + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.2.1': + '@tailwindcss/oxide-linux-x64-musl@4.2.4': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.2.1': + '@tailwindcss/oxide-wasm32-wasi@4.2.4': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.2.1': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.2.1': + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': optional: true - '@tailwindcss/oxide@4.2.1': + '@tailwindcss/oxide@4.2.4': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-arm64': 4.2.1 - '@tailwindcss/oxide-darwin-x64': 4.2.1 - '@tailwindcss/oxide-freebsd-x64': 4.2.1 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.1 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.1 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.1 - '@tailwindcss/oxide-linux-x64-musl': 4.2.1 - '@tailwindcss/oxide-wasm32-wasi': 4.2.1 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.1 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.1 + '@tailwindcss/oxide-android-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-x64': 4.2.4 + '@tailwindcss/oxide-freebsd-x64': 4.2.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-x64-musl': 4.2.4 + '@tailwindcss/oxide-wasm32-wasi': 4.2.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 - '@tailwindcss/vite@4.2.1(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@tailwindcss/vite@4.2.4(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + '@tailwindcss/node': 4.2.4 + '@tailwindcss/oxide': 4.2.4 + tailwindcss: 4.2.4 + vite: 6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0) - '@tanstack/query-core@5.90.20': {} + '@tanstack/query-core@5.100.9': {} - '@tanstack/react-query@5.90.21(react@19.2.4)': + '@tanstack/react-query@5.100.9(react@19.2.5)': dependencies: - '@tanstack/query-core': 5.90.20 - react: 19.2.4 + '@tanstack/query-core': 5.100.9 + react: 19.2.5 '@tybys/wasm-util@0.10.1': dependencies: @@ -5624,7 +4775,7 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 @@ -5636,7 +4787,7 @@ snapshots: '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': @@ -5656,10 +4807,6 @@ snapshots: '@types/estree@1.0.8': {} - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - '@types/json-schema@7.0.15': {} '@types/lodash.isequal@4.5.8': @@ -5668,9 +4815,7 @@ snapshots: '@types/lodash@4.17.24': {} - '@types/node@12.20.55': {} - - '@types/node@22.19.11': + '@types/node@22.19.17': dependencies: undici-types: 6.21.0 @@ -5678,7 +4823,7 @@ snapshots: dependencies: undici-types: 6.19.8 - '@types/node@24.10.13': + '@types/node@24.12.2': dependencies: undici-types: 7.16.0 @@ -5692,139 +4837,106 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@types/unist@3.0.3': {} - '@types/ws@8.18.1': dependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.2 - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 - eslint: 9.39.3(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/type-utils': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.1 + eslint: 9.39.4(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.1 debug: 4.4.3 - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.59.1': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.39.3(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.59.1': {} - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.59.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 debug: 4.4.3 - minimatch: 10.2.4 + minimatch: 10.2.5 semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - eslint: 9.39.3(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.59.1': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.59.1 eslint-visitor-keys: 5.0.1 - '@typescript/native-preview-darwin-arm64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-darwin-x64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-linux-arm64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-linux-arm@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-linux-x64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-win32-arm64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview-win32-x64@7.0.0-dev.20260225.1': - optional: true - - '@typescript/native-preview@7.0.0-dev.20260225.1': - optionalDependencies: - '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20260225.1 - '@typescript/native-preview-darwin-x64': 7.0.0-dev.20260225.1 - '@typescript/native-preview-linux-arm': 7.0.0-dev.20260225.1 - '@typescript/native-preview-linux-arm64': 7.0.0-dev.20260225.1 - '@typescript/native-preview-linux-x64': 7.0.0-dev.20260225.1 - '@typescript/native-preview-win32-arm64': 7.0.0-dev.20260225.1 - '@typescript/native-preview-win32-x64': 7.0.0-dev.20260225.1 - - '@vitejs/plugin-basic-ssl@1.2.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitejs/plugin-basic-ssl@1.2.0(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: - vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0) - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitejs/plugin-react@4.7.0(vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -5832,15 +4944,15 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - ast-v8-to-istanbul: 0.3.11 + ast-v8-to-istanbul: 0.3.12 debug: 4.4.3 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -5851,7 +4963,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vitest: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color @@ -5863,13 +4975,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -5915,15 +5027,13 @@ snapshots: aes-js@4.0.0-beta.5: {} - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-colors@4.1.3: {} - ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -5936,22 +5046,16 @@ snapshots: ansis@4.2.0: {} - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} - array-union@2.1.0: {} - assertion-error@2.0.1: {} ast-kit@2.2.0: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 pathe: 2.0.3 - ast-v8-to-istanbul@0.3.11: + ast-v8-to-istanbul@0.3.12: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 @@ -5959,15 +5063,15 @@ snapshots: asynckit@0.4.0: {} - axios@1.13.5: + axios@1.16.0: dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 form-data: 4.0.5 - proxy-from-env: 1.1.0 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug - b4a@1.8.0: {} + b4a@1.8.1: {} babel-plugin-react-compiler@1.0.0: dependencies: @@ -5983,19 +5087,32 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.10.0: {} + baseline-browser-mapping@2.10.27: {} bech32@2.0.0: {} - better-path-resolve@1.0.0: + bip174@3.0.0: dependencies: - is-windows: 1.0.2 + uint8array-tools: 0.0.9 + varuint-bitcoin: 2.0.0 birpc@4.0.0: {} + bitcoinjs-lib@7.0.1(typescript@5.9.3): + dependencies: + '@noble/hashes': 1.8.0 + bech32: 2.0.0 + bip174: 3.0.0 + bs58check: 4.0.0 + uint8array-tools: 0.0.9 + valibot: 1.3.1(typescript@5.9.3) + varuint-bitcoin: 2.0.0 + transitivePeerDependencies: + - typescript + blake2b-wasm@2.4.0: dependencies: - b4a: 1.8.0 + b4a: 1.8.1 nanoassert: 2.0.0 transitivePeerDependencies: - react-native-b4a @@ -6011,28 +5128,28 @@ snapshots: bn.js@5.2.3: {} - brace-expansion@1.1.12: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@5.0.3: + brace-expansion@2.1.0: dependencies: - balanced-match: 4.0.4 + balanced-match: 1.0.2 - braces@3.0.3: + brace-expansion@5.0.5: dependencies: - fill-range: 7.1.1 + balanced-match: 4.0.4 brorand@1.1.0: {} - browserslist@4.28.1: + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001774 - electron-to-chromium: 1.5.302 - node-releases: 2.0.27 - update-browserslist-db: 1.2.3(browserslist@4.28.1) + baseline-browser-mapping: 2.10.27 + caniuse-lite: 1.0.30001791 + electron-to-chromium: 1.5.349 + node-releases: 2.0.38 + update-browserslist-db: 1.2.3(browserslist@4.28.2) bs58@5.0.0: dependencies: @@ -6061,9 +5178,9 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001774: {} + caniuse-lite@1.0.30001791: {} - cborg@4.5.8: {} + cborg@5.1.1: {} chai@5.3.3: dependencies: @@ -6078,12 +5195,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chardet@2.1.1: {} - check-error@2.1.3: {} - ci-info@3.9.0: {} - cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -6136,8 +5249,6 @@ snapshots: csstype@3.2.3: {} - dataloader@1.4.0: {} - debug@4.4.3: dependencies: ms: 2.1.3 @@ -6148,21 +5259,13 @@ snapshots: deep-is@0.1.4: {} - defu@6.1.4: {} + defu@6.1.7: {} delayed-stream@1.0.0: {} - detect-indent@6.1.0: {} - detect-libc@2.1.2: {} - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - dotenv@17.3.1: {} - - dotenv@8.6.0: {} + dotenv@17.4.2: {} dts-resolver@2.1.3: {} @@ -6174,7 +5277,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.302: {} + electron-to-chromium@1.5.349: {} elliptic@6.6.1: dependencies: @@ -6192,17 +5295,10 @@ snapshots: empathic@2.0.0: {} - enhanced-resolve@5.19.0: + enhanced-resolve@5.21.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 - - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - - entities@4.5.0: {} + tapable: 2.3.3 es-define-property@1.0.1: {} @@ -6219,7 +5315,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 esbuild@0.25.12: optionalDependencies: @@ -6254,38 +5350,38 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)): dependencies: - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.3(jiti@2.6.1)))(eslint@9.39.3(jiti@2.6.1))(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1))(prettier@3.8.3): dependencies: - eslint: 9.39.3(jiti@2.6.1) - prettier: 3.8.1 + eslint: 9.39.4(jiti@2.6.1) + prettier: 3.8.3 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.39.3(jiti@2.6.1)) + eslint-config-prettier: 10.1.8(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.39.3(jiti@2.6.1)): + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.39.4(jiti@2.6.1)): dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.0) - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) hermes-parser: 0.25.1 zod: 3.25.76 zod-validation-error: 3.5.4(zod@3.25.76) transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks@5.2.0(eslint@9.39.3(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@2.6.1)): dependencies: - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.26(eslint@9.39.3(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.26(eslint@9.39.4(jiti@2.6.1)): dependencies: - eslint: 9.39.3(jiti@2.6.1) + eslint: 9.39.4(jiti@2.6.1) eslint-scope@8.4.0: dependencies: @@ -6298,21 +5394,21 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@9.39.3(jiti@2.6.1): + eslint@9.39.4(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.3(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 + '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.4 - '@eslint/js': 9.39.3 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.14.0 + ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -6345,8 +5441,6 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 - esprima@4.0.1: {} - esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -6382,45 +5476,22 @@ snapshots: expect-type@1.3.0: {} - extendable-error@0.1.7: {} - fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.4 file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -6428,12 +5499,12 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.2: {} - follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} foreground-child@3.3.1: dependencies: @@ -6445,21 +5516,9 @@ snapshots: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.3 mime-types: 2.1.35 - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -6481,7 +5540,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 math-intrinsics: 1.1.0 get-proto@1.0.1: @@ -6489,14 +5548,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-tsconfig@4.13.6: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -6505,14 +5560,14 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 3.4.3 - minimatch: 9.0.8 + minimatch: 9.0.9 minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 glob@13.0.6: dependencies: - minimatch: 10.2.4 + minimatch: 10.2.5 minipass: 7.1.3 path-scurry: 2.0.2 @@ -6527,15 +5582,6 @@ snapshots: globals@14.0.0: {} - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -6553,7 +5599,7 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 - hasown@2.0.2: + hasown@2.0.3: dependencies: function-bind: 1.1.2 @@ -6569,23 +5615,17 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - hookable@6.0.1: {} + hookable@6.1.1: {} html-escaper@2.0.2: {} - human-id@4.1.3: {} - - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - ieee754@1.2.1: {} ignore@5.3.2: {} ignore@7.0.5: {} - immutable@4.3.7: {} + immutable@4.3.8: {} import-fresh@3.3.1: dependencies: @@ -6611,23 +5651,15 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-number@7.0.0: {} - - is-subdir@1.2.0: - dependencies: - better-path-resolve: 1.0.0 - - is-windows@1.0.2: {} - isarray@0.0.1: {} isarray@1.0.0: {} isexe@2.0.0: {} - isomorphic-ws@5.0.0(ws@8.19.0): + isomorphic-ws@5.0.0(ws@8.20.0): dependencies: - ws: 8.19.0 + ws: 8.20.0 istanbul-lib-coverage@3.2.2: {} @@ -6666,11 +5698,6 @@ snapshots: js-xxhash@1.0.4: {} - js-yaml@3.14.2: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -6689,10 +5716,6 @@ snapshots: json5@2.2.3: {} - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -6702,58 +5725,54 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.31.1: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.31.1: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.31.1: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.31.1: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.31.1: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.31.1: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.31.1: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.31.1: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.31.1: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.31.1: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.31.1: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.31.1: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.31.1 - lightningcss-darwin-arm64: 1.31.1 - lightningcss-darwin-x64: 1.31.1 - lightningcss-freebsd-x64: 1.31.1 - lightningcss-linux-arm-gnueabihf: 1.31.1 - lightningcss-linux-arm64-gnu: 1.31.1 - lightningcss-linux-arm64-musl: 1.31.1 - lightningcss-linux-x64-gnu: 1.31.1 - lightningcss-linux-x64-musl: 1.31.1 - lightningcss-win32-arm64-msvc: 1.31.1 - lightningcss-win32-x64-msvc: 1.31.1 - - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 lit-element@4.2.2: dependencies: @@ -6771,10 +5790,6 @@ snapshots: lit-element: 4.2.2 lit-html: 3.3.2 - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -6783,27 +5798,23 @@ snapshots: lodash.merge@4.6.2: {} - lodash.startcase@4.4.0: {} - loupe@3.2.1: {} lru-cache@10.4.3: {} - lru-cache@11.2.6: {} + lru-cache@11.3.5: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lunr@2.3.9: {} - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 magicast@0.3.5: dependencies: - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 source-map-js: 1.2.1 @@ -6811,26 +5822,8 @@ snapshots: dependencies: semver: 7.7.4 - markdown-it@14.1.1: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - math-intrinsics@1.1.0: {} - mdurl@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - mime-db@1.52.0: {} mime-types@2.1.35: @@ -6841,31 +5834,29 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} - minimatch@10.2.4: + minimatch@10.2.5: dependencies: - brace-expansion: 5.0.3 + brace-expansion: 5.0.5 minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.14 - minimatch@9.0.8: + minimatch@9.0.9: dependencies: - brace-expansion: 5.0.3 + brace-expansion: 2.1.0 minipass@7.1.3: {} mkdirp@1.0.4: {} - mri@1.2.0: {} - ms@2.1.3: {} multiformats@13.4.2: {} nanoassert@2.0.0: {} - nanoid@3.3.11: {} + nanoid@3.3.12: {} natural-compare@1.4.0: {} @@ -6873,7 +5864,7 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-releases@2.0.27: {} + node-releases@2.0.38: {} noms@0.0.0: dependencies: @@ -6895,38 +5886,16 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - outdent@0.5.0: {} - - p-filter@2.1.0: - dependencies: - p-map: 2.1.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-map@2.1.0: {} - - p-try@2.2.0: {} - package-json-from-dist@1.0.1: {} - package-manager-detector@0.2.11: - dependencies: - quansync: 0.2.11 - parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -6944,26 +5913,20 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.2.6 + lru-cache: 11.3.5 minipass: 7.1.3 - path-type@4.0.0: {} - pathe@2.0.3: {} pathval@2.0.1: {} picocolors@1.1.1: {} - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pify@4.0.1: {} + picomatch@4.0.4: {} - postcss@8.5.6: + postcss@8.5.13: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -6973,50 +5936,29 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3): + prettier-plugin-organize-imports@4.3.0(prettier@3.8.3)(typescript@5.9.3): dependencies: - prettier: 3.8.1 + prettier: 3.8.3 typescript: 5.9.3 - prettier-plugin-tailwindcss@0.6.14(prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3))(prettier@3.8.1): - dependencies: - prettier: 3.8.1 - optionalDependencies: - prettier-plugin-organize-imports: 4.3.0(prettier@3.8.1)(typescript@5.9.3) - - prettier@2.8.8: {} - - prettier@3.8.1: {} + prettier@3.8.3: {} process-nextick-args@2.0.1: {} - proxy-from-env@1.1.0: {} - - punycode.js@2.3.1: {} + proxy-from-env@2.1.0: {} punycode@2.3.1: {} - quansync@0.2.11: {} - quansync@1.0.0: {} - queue-microtask@1.2.3: {} - - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 react-refresh@0.17.0: {} - react@19.2.4: {} - - read-yaml-file@1.1.0: - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.14.2 - pify: 4.0.1 - strip-bom: 3.0.0 + react@19.2.5: {} readable-stream@1.0.34: dependencies: @@ -7039,35 +5981,30 @@ snapshots: resolve-from@4.0.0: {} - resolve-from@5.0.0: {} - resolve-pkg-maps@1.0.0: {} - reusify@1.1.0: {} - rimraf@6.1.3: dependencies: glob: 13.0.6 package-json-from-dist: 1.0.1 - rolldown-plugin-dts@0.20.0(@typescript/native-preview@7.0.0-dev.20260225.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3): + rolldown-plugin-dts@0.20.0(rolldown@1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(typescript@5.9.3): dependencies: '@babel/generator': 7.29.1 - '@babel/parser': 7.29.0 + '@babel/parser': 7.29.3 '@babel/types': 7.29.0 ast-kit: 2.2.0 birpc: 4.0.0 dts-resolver: 2.1.3 - get-tsconfig: 4.13.6 + get-tsconfig: 4.14.0 obug: 2.1.1 - rolldown: 1.0.0-beta.58 + rolldown: 1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optionalDependencies: - '@typescript/native-preview': 7.0.0-dev.20260225.1 typescript: 5.9.3 transitivePeerDependencies: - oxc-resolver - rolldown@1.0.0-beta.58: + rolldown@1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): dependencies: '@oxc-project/types': 0.106.0 '@rolldown/pluginutils': 1.0.0-beta.58 @@ -7082,68 +6019,67 @@ snapshots: '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.58 '@rolldown/binding-linux-x64-musl': 1.0.0-beta.58 '@rolldown/binding-openharmony-arm64': 1.0.0-beta.58 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.58 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.58 '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.58 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - rolldown@1.0.0-rc.3: + rolldown@1.0.0-rc.17: dependencies: - '@oxc-project/types': 0.112.0 - '@rolldown/pluginutils': 1.0.0-rc.3 + '@oxc-project/types': 0.127.0 + '@rolldown/pluginutils': 1.0.0-rc.17 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.3 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.3 - '@rolldown/binding-darwin-x64': 1.0.0-rc.3 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.3 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.3 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.3 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.3 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.3 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.3 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.3 - - rollup@4.59.0: + '@rolldown/binding-android-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-x64': 1.0.0-rc.17 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 + + rollup@4.60.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 + '@rollup/rollup-android-arm-eabi': 4.60.2 + '@rollup/rollup-android-arm64': 4.60.2 + '@rollup/rollup-darwin-arm64': 4.60.2 + '@rollup/rollup-darwin-x64': 4.60.2 + '@rollup/rollup-freebsd-arm64': 4.60.2 + '@rollup/rollup-freebsd-x64': 4.60.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 + '@rollup/rollup-linux-arm-musleabihf': 4.60.2 + '@rollup/rollup-linux-arm64-gnu': 4.60.2 + '@rollup/rollup-linux-arm64-musl': 4.60.2 + '@rollup/rollup-linux-loong64-gnu': 4.60.2 + '@rollup/rollup-linux-loong64-musl': 4.60.2 + '@rollup/rollup-linux-ppc64-gnu': 4.60.2 + '@rollup/rollup-linux-ppc64-musl': 4.60.2 + '@rollup/rollup-linux-riscv64-gnu': 4.60.2 + '@rollup/rollup-linux-riscv64-musl': 4.60.2 + '@rollup/rollup-linux-s390x-gnu': 4.60.2 + '@rollup/rollup-linux-x64-gnu': 4.60.2 + '@rollup/rollup-linux-x64-musl': 4.60.2 + '@rollup/rollup-openbsd-x64': 4.60.2 + '@rollup/rollup-openharmony-arm64': 4.60.2 + '@rollup/rollup-win32-arm64-msvc': 4.60.2 + '@rollup/rollup-win32-ia32-msvc': 4.60.2 + '@rollup/rollup-win32-x64-gnu': 4.60.2 + '@rollup/rollup-win32-x64-msvc': 4.60.2 fsevents: 2.3.3 - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - safe-buffer@5.1.2: {} - safer-buffer@2.1.2: {} - scheduler@0.27.0: {} scrypt-js@3.0.1: {} @@ -7166,17 +6102,8 @@ snapshots: signal-exit@4.1.0: {} - slash@3.0.0: {} - source-map-js@1.2.1: {} - spawndamnit@3.0.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - sprintf-js@1.0.3: {} - stackback@0.0.2: {} std-env@3.10.0: {} @@ -7191,7 +6118,7 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 string_decoder@0.10.31: {} @@ -7203,12 +6130,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 - strip-bom@3.0.0: {} - strip-json-comments@3.1.1: {} strip-literal@3.1.0: @@ -7223,17 +6148,15 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 - tailwindcss@4.2.1: {} - - tapable@2.3.0: {} + tailwindcss@4.2.4: {} - term-size@2.2.1: {} + tapable@2.3.3: {} test-exclude@7.0.2: dependencies: - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 glob: 10.5.0 - minimatch: 10.2.4 + minimatch: 10.2.5 through2@2.0.5: dependencies: @@ -7244,12 +6167,12 @@ snapshots: tinyexec@0.3.2: {} - tinyexec@1.0.2: {} + tinyexec@1.1.2: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 tinypool@1.1.1: {} @@ -7257,39 +6180,37 @@ snapshots: tinyspy@4.0.4: {} - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - tr46@0.0.3: {} tree-kill@1.2.2: {} - ts-api-utils@2.4.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - tsdown@0.19.0-beta.3(@typescript/native-preview@7.0.0-dev.20260225.1)(synckit@0.11.12)(typescript@5.9.3): + tsdown@0.19.0-beta.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(synckit@0.11.12)(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 - defu: 6.1.4 + defu: 6.1.7 empathic: 2.0.0 - hookable: 6.0.1 + hookable: 6.1.1 import-without-cache: 0.2.5 obug: 2.1.1 - picomatch: 4.0.3 - rolldown: 1.0.0-beta.58 - rolldown-plugin-dts: 0.20.0(@typescript/native-preview@7.0.0-dev.20260225.1)(rolldown@1.0.0-beta.58)(typescript@5.9.3) + picomatch: 4.0.4 + rolldown: 1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + rolldown-plugin-dts: 0.20.0(rolldown@1.0.0-beta.58(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(typescript@5.9.3) semver: 7.7.4 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 tree-kill: 1.2.2 unconfig-core: 7.5.0 - unrun: 0.2.27(synckit@0.11.12) + unrun: 0.2.37(synckit@0.11.12) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' - '@ts-macro/tsc' - '@typescript/native-preview' - oxc-resolver @@ -7309,29 +6230,22 @@ snapshots: type-fest@4.6.0: {} - typedoc@0.28.7(typescript@5.9.3): + typescript-eslint@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.22.0 - lunr: 2.3.9 - markdown-it: 14.1.1 - minimatch: 9.0.8 - typescript: 5.9.3 - yaml: 2.8.2 - - typescript-eslint@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.3(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.3(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} - uc.micro@2.1.0: {} + uint8array-tools@0.0.8: {} + + uint8array-tools@0.0.9: {} unconfig-core@7.5.0: dependencies: @@ -7346,19 +6260,17 @@ snapshots: undici-types@7.16.0: {} - universalify@0.1.2: {} - - unrun@0.2.27(synckit@0.11.12): + unrun@0.2.37(synckit@0.11.12): dependencies: - rolldown: 1.0.0-rc.3 + rolldown: 1.0.0-rc.17 optionalDependencies: synckit: 0.11.12 untildify@4.0.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.1): + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.28.1 + browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -7370,17 +6282,21 @@ snapshots: uuid@8.3.2: {} - valibot@1.2.0(typescript@5.9.3): + valibot@1.3.1(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 - vite-node@3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + varuint-bitcoin@2.0.0: + dependencies: + uint8array-tools: 0.0.8 + + vite-node@3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - jiti @@ -7395,41 +6311,39 @@ snapshots: - tsx - yaml - vite@6.4.1(@types/node@22.19.11)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + vite@6.4.2(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.13 + rollup: 4.60.2 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 22.19.11 + '@types/node': 22.19.17 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.31.1 - yaml: 2.8.2 + lightningcss: 1.32.0 - vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + vite@6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0): dependencies: esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.59.0 - tinyglobby: 0.2.15 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.13 + rollup: 4.60.2 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.2 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.31.1 - yaml: 2.8.2 + lightningcss: 1.32.0 - vitest@3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2): + vitest@3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -7440,18 +6354,18 @@ snapshots: expect-type: 1.3.0 magic-string: 0.30.21 pathe: 2.0.3 - picomatch: 4.0.3 + picomatch: 4.0.4 std-env: 3.10.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.31.1)(yaml@2.8.2) + vite: 6.4.2(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) + vite-node: 3.2.4(@types/node@24.12.2)(jiti@2.6.1)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.10.13 + '@types/node': 24.12.2 transitivePeerDependencies: - jiti - less @@ -7494,13 +6408,13 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrappy@1.0.2: {} ws@8.17.1: {} - ws@8.19.0: {} + ws@8.20.0: {} xtend@4.0.2: {} @@ -7508,8 +6422,6 @@ snapshots: yallist@3.1.1: {} - yaml@2.8.2: {} - yargs-parser@20.2.9: {} yargs@16.2.0: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f1b0c9a..b11e2a5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,19 +1,29 @@ packages: - packages/* - apps/* - # @generated begin forker-workspaces - - forks/ccc/packages/* - - "!forks/ccc/packages/demo" - - "!forks/ccc/packages/docs" - - "!forks/ccc/packages/examples" - - "!forks/ccc/packages/faucet" - - "!forks/ccc/packages/playground" - - "!forks/ccc/packages/tests" - # @generated end forker-workspaces + # Local CCC workspace when materialized via `pnpm forks:bootstrap`. + - forks/ccc/repo/packages/* + - "!forks/ccc/repo/packages/demo" + - "!forks/ccc/repo/packages/docs" + - "!forks/ccc/repo/packages/examples" + - "!forks/ccc/repo/packages/faucet" + - "!forks/ccc/repo/packages/playground" + - "!forks/ccc/repo/packages/tests" + +overrides: + # Keep published manifests on `catalog:` while forcing the materialized + # local CCC workspace to satisfy direct stack dependencies during installs. + # Update this list alongside any new direct `@ckb-ccc/*` dependency. + "@ckb-ccc/ccc": workspace:* + "@ckb-ccc/core": workspace:* + "@ckb-ccc/udt": workspace:* catalog: + # Catalog tracks published fallback versions; forks/config.json only owns the + # local clone refs that pnpm forks:bootstrap materializes under forks/ccc/repo. + "@ckb-ccc/ccc": ^1.1.21 "@ckb-ccc/core": ^1.12.2 - "@ckb-ccc/udt": ^1.12.2 + "@ckb-ccc/udt": ^0.1.24 "@types/node": ^24.8.1 minimumReleaseAge: 1440 diff --git a/prettier.config.cjs b/prettier.config.cjs deleted file mode 100644 index 5e18103..0000000 --- a/prettier.config.cjs +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @see https://prettier.io/docs/configuration - * @type {import("prettier").Config} - */ -const config = { - singleQuote: false, - trailingComma: "all", - plugins: [require.resolve("prettier-plugin-organize-imports")], -}; - -module.exports = config; diff --git a/scripts/check-ccc-overrides.mjs b/scripts/check-ccc-overrides.mjs new file mode 100644 index 0000000..e3ed3fb --- /dev/null +++ b/scripts/check-ccc-overrides.mjs @@ -0,0 +1,96 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = fileURLToPath(new URL("..", import.meta.url)); +const workspacePath = join(rootDir, "pnpm-workspace.yaml"); +const workspaceText = readFileSync(workspacePath, "utf8"); +const overrides = parseOverrides(workspaceText); +const directCccDeps = collectDirectCccDeps(rootDir); + +const problems = []; +for (const [name, consumers] of directCccDeps.entries()) { + const override = overrides.get(name); + if (override === undefined) { + problems.push({ + name, + reason: "missing root override", + consumers, + }); + continue; + } + if (override !== "workspace:*") { + problems.push({ + name, + reason: `override is ${override}, expected workspace:*`, + consumers, + }); + } +} + +if (problems.length > 0) { + console.error("Direct @ckb-ccc/* dependencies must be covered by root workspace overrides:"); + for (const problem of problems) { + console.error(`- ${problem.name}: ${problem.reason}`); + console.error(` consumers: ${problem.consumers.join(", ")}`); + } + process.exit(1); +} + +console.log( + `Verified ${directCccDeps.size} direct @ckb-ccc/* dependencies against root overrides.`, +); + +function collectDirectCccDeps(root) { + const manifests = [join(root, "package.json")]; + for (const group of ["packages", "apps"]) { + const groupDir = join(root, group); + for (const entry of readdirSync(groupDir, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + manifests.push(join(groupDir, entry.name, "package.json")); + } + } + + const deps = new Map(); + for (const manifestPath of manifests) { + const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); + const label = relativeLabel(root, manifestPath); + for (const field of [ + "dependencies", + "devDependencies", + "optionalDependencies", + "peerDependencies", + ]) { + for (const depName of Object.keys(manifest[field] ?? {})) { + if (!depName.startsWith("@ckb-ccc/")) continue; + const consumers = deps.get(depName) ?? []; + consumers.push(`${label} (${field})`); + deps.set(depName, consumers); + } + } + } + return deps; +} + +function parseOverrides(workspaceYaml) { + const overrides = new Map(); + let inOverrides = false; + for (const line of workspaceYaml.split(/\r?\n/u)) { + if (!inOverrides) { + if (line === "overrides:") inOverrides = true; + continue; + } + if (/^\S/u.test(line)) break; + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const match = line.match(/^\s{2}"([^"]+)":\s*(\S.*?)\s*$/u); + if (match) { + overrides.set(match[1], match[2]); + } + } + return overrides; +} + +function relativeLabel(root, filePath) { + return filePath.slice(root.length + 1, -"/package.json".length); +} diff --git a/scripts/forks-bootstrap.mjs b/scripts/forks-bootstrap.mjs new file mode 100644 index 0000000..eca8741 --- /dev/null +++ b/scripts/forks-bootstrap.mjs @@ -0,0 +1,41 @@ +import { mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { spawnSync } from "node:child_process"; + +const rootDir = fileURLToPath(new URL("..", import.meta.url)); +const forksDir = join(rootDir, "forks"); +const configPath = join(forksDir, "config.json"); +const stageDir = join(forksDir, ".stage"); +const stagePrefix = join(stageDir, "bootstrap-phroi_forker."); + +const config = JSON.parse(readFileSync(configPath, "utf8")); +const upstream = config.phroi_forker?.upstream; + +if (typeof upstream !== "string" || upstream.length === 0) { + throw new Error("forks/config.json must define phroi_forker.upstream"); +} + +// Bootstrap from a temporary forker checkout so plain stack checkouts do not +// need an existing local tool clone before materializing forks/. +mkdirSync(stageDir, { recursive: true }); +const tempDir = mkdtempSync(stagePrefix); + +try { + const toolDir = join(tempDir, "repo"); + run("git", ["clone", "--filter=blob:none", "--depth", "1", upstream, toolDir]); + run("bash", [join(toolDir, "materialize-workspace.sh")]); +} finally { + rmSync(tempDir, { recursive: true, force: true }); +} + +function run(command, args) { + const result = spawnSync(command, args, { + cwd: rootDir, + stdio: "inherit", + }); + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} diff --git a/scripts/forks-ccc-smoke.mjs b/scripts/forks-ccc-smoke.mjs new file mode 100644 index 0000000..a480dd4 --- /dev/null +++ b/scripts/forks-ccc-smoke.mjs @@ -0,0 +1,45 @@ +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const rootDir = fileURLToPath(new URL("..", import.meta.url)); +const targets = [ + { + filter: "@ickb/utils", + script: + "const mod = await import('@ckb-ccc/core'); if (!('ccc' in mod)) throw new Error('Missing ccc namespace export from @ckb-ccc/core');", + }, + { + filter: "@ickb/core", + script: + "const mod = await import('@ckb-ccc/udt'); if (!('udt' in mod)) throw new Error('Missing udt namespace export from @ckb-ccc/udt');", + }, + { + filter: "interface", + script: + "const mod = await import('@ckb-ccc/ccc'); if (!('ccc' in mod) || !('JoyId' in mod) || !('Transaction' in mod)) throw new Error('Missing expected @ckb-ccc/ccc exports');", + }, +]; + +for (const target of targets) { + // Run the import from the real consumer package so resolution matches + // the downstream path we want to validate, not the repo root. + const result = spawnSync( + "pnpm", + [ + "--filter", + target.filter, + "exec", + "node", + "--input-type=module", + "-e", + target.script, + ], + { + cwd: rootDir, + stdio: "inherit", + }, + ); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} diff --git a/scripts/forks-ccc.mjs b/scripts/forks-ccc.mjs new file mode 100644 index 0000000..ed5ab63 --- /dev/null +++ b/scripts/forks-ccc.mjs @@ -0,0 +1,235 @@ +import { spawn, spawnSync } from "node:child_process"; +import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = fileURLToPath(new URL("..", import.meta.url)); +const cccDir = join(rootDir, "forks", "ccc", "repo"); +const json = process.argv.includes("--json"); +const planOnly = json || process.argv.includes("--plan"); +const watch = process.argv.includes("--watch"); +const watchCommand = + "test -f misc/basedirs/dist/package.json && mkdir -p dist && cp misc/basedirs/dist/package.json dist/package.json; rm -rf dist.commonjs; exec tsc --watch --incremental false --preserveWatchOutput --rootDir src"; + +if (!existsSync(join(cccDir, "package.json"))) { + console.error("Missing forks/ccc/repo. Run pnpm forks:bootstrap first."); + process.exit(1); +} + +const directDeps = collectDirectCccDeps(rootDir); +const directRoots = [...directDeps.keys()].sort(); +if (directRoots.length === 0) { + console.error("No direct @ckb-ccc/* dependencies found in the stack workspace."); + process.exit(1); +} + +const cccPackages = collectCccPackages(cccDir); +const buildSurface = [...collectClosure(directRoots, directDeps, cccPackages)].sort(); +const watchSurface = buildSurface.filter((name) => isTscWatchPackage(cccPackages.get(name))); +const prebuildSurface = buildSurface.filter((name) => !watchSurface.includes(name)); +const plan = { + roots: directRoots, + buildSurface, + watchSurface, + prebuildSurface, +}; + +if (planOnly) { + if (json) { + console.log(JSON.stringify(plan, null, 2)); + } else { + printPlan(plan, { includeWatchSurface: true }); + } + process.exit(0); +} + +printPlan(plan, { includeWatchSurface: watch }); + +if (watch) { + if (prebuildSurface.length > 0) { + runPnpm([...packageFilters(prebuildSurface), "run", "build"]); + } + + runWatch(watchSurface); +} else { + runPnpm([...packageFilters(buildSurface), "run", "build"]); + cleanupTsBuildInfo(watchSurface, cccPackages); +} + +function printPlan(plan, { includeWatchSurface }) { + console.log(`CCC roots (${plan.roots.length}): ${plan.roots.join(", ")}`); + console.log( + `CCC build surface (${plan.buildSurface.length}): ${plan.buildSurface.join(", ")}`, + ); + if (!includeWatchSurface) return; + console.log( + `CCC watch prebuild-only surface (${plan.prebuildSurface.length}): ${plan.prebuildSurface.join(", ")}`, + ); + console.log( + `CCC watch surface (${plan.watchSurface.length}): ${plan.watchSurface.join(", ")}`, + ); +} + +function collectDirectCccDeps(root) { + const manifests = [join(root, "package.json")]; + for (const group of ["packages", "apps"]) { + const groupDir = join(root, group); + for (const entry of readdirSync(groupDir, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + manifests.push(join(groupDir, entry.name, "package.json")); + } + } + + const deps = new Map(); + for (const manifestPath of manifests) { + const manifest = readJson(manifestPath); + for (const field of [ + "dependencies", + "devDependencies", + "optionalDependencies", + "peerDependencies", + ]) { + for (const depName of Object.keys(manifest[field] ?? {})) { + if (!depName.startsWith("@ckb-ccc/")) continue; + const consumers = deps.get(depName) ?? []; + consumers.push(manifestPath); + deps.set(depName, consumers); + } + } + } + + return deps; +} + +function collectCccPackages(root) { + const packagesDir = join(root, "packages"); + const packages = new Map(); + for (const entry of readdirSync(packagesDir, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const dir = join(packagesDir, entry.name); + const manifestPath = join(dir, "package.json"); + if (!existsSync(manifestPath)) continue; + const manifest = readJson(manifestPath); + packages.set(manifest.name, { + dir, + manifest, + buildScript: manifest.scripts?.build, + }); + } + return packages; +} + +function collectClosure(roots, directDeps, cccPackages) { + const closure = new Set(); + + const visit = (packageName, consumer) => { + if (closure.has(packageName)) return; + + const pkg = cccPackages.get(packageName); + if (!pkg) { + const from = consumer ? ` required by ${consumer}` : ""; + throw new Error(`Missing local CCC package for ${packageName}${from}.`); + } + + closure.add(packageName); + for (const depName of Object.keys(pkg.manifest.dependencies ?? {})) { + if (!depName.startsWith("@ckb-ccc/")) continue; + visit(depName, packageName); + } + }; + + for (const root of roots) { + visit(root, directDeps.get(root)?.[0]); + } + + return closure; +} + +function isTscWatchPackage(pkg) { + return Boolean(pkg?.buildScript?.includes("tsc") && !pkg.buildScript.includes("tsdown")); +} + +function packageFilters(packages) { + return [ + "--dir", + cccDir, + "-r", + ...packages.flatMap((name) => ["--filter", name]), + ]; +} + +function runPnpm(args) { + const result = spawnSync("pnpm", args, { + cwd: rootDir, + stdio: "inherit", + }); + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +function runWatch(packages) { + const child = spawn( + "pnpm", + [ + "--dir", + cccDir, + "-r", + "--parallel", + ...packages.flatMap((name) => ["--filter", name]), + "exec", + "sh", + "-c", + watchCommand, + ], + { + cwd: rootDir, + detached: true, + stdio: "inherit", + }, + ); + + const forwardSignal = (signal) => { + if (child.pid) { + try { + process.kill(-child.pid, signal); + } catch { + child.kill(signal); + } + } + }; + + process.on("SIGINT", () => forwardSignal("SIGINT")); + process.on("SIGTERM", () => forwardSignal("SIGTERM")); + child.on("error", (error) => { + console.error(error.message); + process.exit(1); + }); + child.on("exit", (code, signal) => { + cleanupTsBuildInfo(watchSurface, cccPackages); + process.exit(code ?? signalExitCode(signal)); + }); +} + +function readJson(filePath) { + return JSON.parse(readFileSync(filePath, "utf8")); +} + +function cleanupTsBuildInfo(packages, cccPackages) { + for (const name of packages) { + rmSync(join(cccPackages.get(name).dir, "tsconfig.tsbuildinfo"), { + force: true, + }); + } +} + +function signalExitCode(signal) { + switch (signal) { + case "SIGINT": + return 130; + case "SIGTERM": + return 143; + default: + return 1; + } +} diff --git a/scripts/forks-ccc.test.mjs b/scripts/forks-ccc.test.mjs new file mode 100644 index 0000000..729e58a --- /dev/null +++ b/scripts/forks-ccc.test.mjs @@ -0,0 +1,67 @@ +import assert from "node:assert/strict"; +import { spawnSync } from "node:child_process"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import test from "node:test"; +import { fileURLToPath } from "node:url"; + +const rootDir = fileURLToPath(new URL("..", import.meta.url)); +const cccDir = join(rootDir, "forks", "ccc", "repo"); + +test( + "forks-ccc --json reports the current stack-owned CCC surfaces", + { skip: !existsSync(join(cccDir, "package.json")) }, + () => { + const result = spawnSync("node", ["scripts/forks-ccc.mjs", "--json"], { + cwd: rootDir, + encoding: "utf8", + }); + + assert.equal(result.status, 0, result.stderr); + + const plan = JSON.parse(result.stdout); + assert.deepEqual(plan.roots, [ + "@ckb-ccc/ccc", + "@ckb-ccc/core", + "@ckb-ccc/udt", + ]); + assert.deepEqual(plan.buildSurface, [ + "@ckb-ccc/ccc", + "@ckb-ccc/core", + "@ckb-ccc/did-ckb", + "@ckb-ccc/eip6963", + "@ckb-ccc/joy-id", + "@ckb-ccc/nip07", + "@ckb-ccc/okx", + "@ckb-ccc/rei", + "@ckb-ccc/shell", + "@ckb-ccc/spore", + "@ckb-ccc/ssri", + "@ckb-ccc/type-id", + "@ckb-ccc/udt", + "@ckb-ccc/uni-sat", + "@ckb-ccc/utxo-global", + "@ckb-ccc/xverse", + ]); + assert.deepEqual(plan.watchSurface, [ + "@ckb-ccc/ccc", + "@ckb-ccc/core", + "@ckb-ccc/eip6963", + "@ckb-ccc/joy-id", + "@ckb-ccc/nip07", + "@ckb-ccc/okx", + "@ckb-ccc/rei", + "@ckb-ccc/shell", + "@ckb-ccc/spore", + "@ckb-ccc/ssri", + "@ckb-ccc/udt", + "@ckb-ccc/uni-sat", + "@ckb-ccc/utxo-global", + "@ckb-ccc/xverse", + ]); + assert.deepEqual(plan.prebuildSurface, [ + "@ckb-ccc/did-ckb", + "@ckb-ccc/type-id", + ]); + }, +); diff --git a/tsgo-filter.sh b/tsgo-filter.sh deleted file mode 100644 index 2734887..0000000 --- a/tsgo-filter.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash - -# tsgo wrapper that filters diagnostics from managed fork source files. -# -# Stack packages import fork .ts source directly for real-time type feedback -# across the fork/stack boundary. This means tsgo checks fork files under the -# stack's stricter tsconfig (verbatimModuleSyntax, noImplicitOverride, -# noUncheckedIndexedAccess) — rules forks may not follow. These aren't real -# integration errors, just tsconfig-strictness mismatches. -# -# This wrapper: -# 1. Reads fork entry names from forks/config.json -# 2. If none are cloned, runs plain tsgo (no filtering needed) -# 3. Otherwise runs tsgo with noEmitOnError=false so fork diagnostics don't block emit -# 4. Reports only diagnostics from stack source files -# 5. Exits non-zero only on real stack errors - -set -euo pipefail - -ROOT="$(cd "$(dirname "$0")" && pwd)" - -# Build filter pattern from cloned fork entries -FILTER_PARTS=() -for name in $(jq -r 'keys[]' "$ROOT/forks/config.json" 2>/dev/null); do - [ -d "$ROOT/forks/$name" ] && FILTER_PARTS+=("forks/$name/") -done - -# No managed repos cloned — run plain tsgo -if [ ${#FILTER_PARTS[@]} -eq 0 ]; then - exec pnpm tsgo -fi - -# Build AWK filter pattern (pipe-separated) -FILTER_PATTERN=$(printf '%s\n' "${FILTER_PARTS[@]}" | paste -sd'|') - -output=$(pnpm tsgo --noEmitOnError false 2>&1) || true - -# Filter out diagnostic blocks originating from fork paths. -# A diagnostic block = a non-indented line (the error) + subsequent indented lines (details). -filtered=$(printf '%s\n' "$output" | awk -v pat="$FILTER_PATTERN" ' - !/^[[:space:]]/ { skip = ($0 ~ pat) ? 1 : 0 } - !skip { print } -') - -if printf '%s\n' "$filtered" | grep -q 'error TS'; then - printf '%s\n' "$filtered" - exit 1 -fi diff --git a/typedoc.base.json b/typedoc.base.json deleted file mode 100644 index 8311282..0000000 --- a/typedoc.base.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "sourceLinkTemplate": "https://github.com/ickb/stack/blob/master/{path}#L{line}", - "excludeReferences": true, - "excludeExternals": true, - "externalPattern": [ - "**/dist/**", - "**/node_modules/**" - ], - "sort": [ - "source-order", - "alphabetical", - "kind" - ] -} \ No newline at end of file diff --git a/typedoc.config.mjs b/typedoc.config.mjs deleted file mode 100644 index e56c009..0000000 --- a/typedoc.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -/** @type {Partial} */ -const config = { - $schema: "https://typedoc.org/schema.json", - name: "iCKB Stack Docs", - entryPoints: ["packages/*"], - entryPointStrategy: "packages", - readme: "README.md", - // theme/plugin-specific options removed or moved to plugin config -}; - -export default config;