CellScript 0.22.0 Release Note
CellScript 0.22 is out.
You can install it with a single command, but the more important story lies underneath. Verification logic that once lived in strings, conventions, or implicit assumptions is now typed, finite, and explicit. Every proof obligation identifies who is responsible for discharging it, while the release gate binds clean source, pinned CKB source and binary provenance, generated artefacts, and committed transaction evidence into a single, auditable hand-off.
The CellScript compiler and toolchain also now include preliminary integrations for RGB++, Spore, and Fiber, together with working examples for each.
Install
curl -fsSL https://raw.githubusercontent.com/CellScript-Labs/CellScript/main/scripts/install.sh | sh
(4 platform binaries + install.sh + SHA256SUMS on the GitHub release.)
Source builds and contributors need Rust 1.97.1 — all in-tree crates moved to Edition 2024 this cycle:
git clone --recurse-submodules https://github.com/CellScript-Labs/CellScript.git
cd CellScript
cargo install --locked --path .
1. Verification logic is now typed, finite, and explicit
The 0.22 language line (nightly-0.22) makes a class of intent that 0.21 recorded as metadata into something the compiler and the generated verifier actually check. The headline additions:
- Typed read-only transaction views —
InputView<T>,OutputView<T>,CellDepView,HeaderDepView,WitnessArgsView,OutPoint,ScriptView. Their metadata records source, ownership, the absence of lifecycle authority, and the checked-static / checked-runtime evidence. The oldsource::*functions stay as the explicit low-level migration surface. - Finite invariant quantifiers —
forall <role> <binding> in <source_view<T>> { require ... }andcount(<source_view<T>> where ...). Closed aggregate target, unbounded and impure bodies rejected. - Source-aware bounded collections —
input-qualifiedBoundedCellSet<CellType, N>discharged byconsume_each,witness-qualified fixed-widthBoundedList<Plan, N>drivingcreate_each. GenericVec<Resource>stays rejected. - A closed, versioned capability algebra — no inheritance syntax;
destroyderives exactlyconsume + burn,replace_uniquerequiresreplaceplus the type’s exact declared identity policy. Schema 51 records per-type capability-set version and required/provided/entailed/missing proofs, and rejects transitive authority from container-like resources. - Concrete fixed-width payload enums — constructor calls, exhaustive destructuring, packed one-byte-tag layouts, arm-local linear Cell ownership, and a pure-helper register-pair return ABI up to 16 bytes. Dynamic, recursive, and generic payloads still fail closed.
- Canonical type
validityblocks — pure field predicates lower to fail-closed checks before selected create/constructor instructions. The only approved environment read isenv::block_number(), recorded as an explicitbuilder-evidence-requiredheader-dep obligation, because CKB-VM has no ambient tip-height syscall. Unknownenv::*, transaction-view reads, and lifecycle syntax inside validity are rejected. - Compile-time-only
borrow root as view { ... }regions —View<T>access to linear Cells with no layout, storage, serialization, or ABI representation. Escape, root lifecycle crossing, and calls outsidePure/ReadOnlyhelpers fail closed. - Enum-backed flows with one initial state, explicit terminal states, and checked terminal-by-output-state evidence; checked casts; transitive callable-effect checking; and deterministic participant-role candidates in ProtocolGraph metadata (selected source published, every candidate published,
authorization_proven = false, roles intentionally absent from ProofPlan).
If you’ve been encoding these patterns in witness conventions or action-name-specific comments, you can stop. And the compiler still fails closed on dynamic or recursive payload ADTs, unbounded resource iteration, authority borrowed from a container, and escaping borrow views.
2. Every proof obligation now says who has to discharge it
This is the change that matters most for auditors. Every ProofPlan record now identifies exactly one of six evidence tiers:
| Tier | Who or what must discharge it |
|---|---|
checked-static |
Compiler or static analysis |
checked-runtime |
Generated verifier code |
runtime-helper-required |
A known helper the selected artifact hasn’t emitted |
builder-evidence-required |
Transaction builder or indexer |
metadata-only |
Audit metadata with no executable enforcement |
chain-evidence-required |
Dry-run, tx-pool, commit, capacity, or cycle evidence |
--production rejects enforcement-like claims that remain metadata-only. It does not silently promote builder or chain obligations into compiler proof — a successful compile is useful evidence, but it is not by itself proof that a transaction can be built, accepted, or committed.
The hand-off is now explicit:
3. --json is the one machine interface, and diagnostics have stable codes
The CLI ergonomics pass consolidates what 0.21 hinted at:
--jsonis the canonical machine-output switch. Success and failure emit exactly one JSON document on stdout. The hidden--message-format=jsonspelling stays temporarily for compatibility.- Stable
E2xxxbackend diagnostics. JSON diagnostics carry the code, name, description, and recovery hint;cellc explain E2202 --jsonexposes the same registry. LSP diagnostics carry the standardcodefield plus acodeDescriptionlink. - Unified run metrics.
cellc run --jsonoutput for VM and simulator now shares one schema, usingnullwhen cycles or steps are unavailable. - Unicode source snippets rendered by terminal width, exit codes classified, error causes preserved, core command rendering centralised, and MCP documentation reads made UTF-8-safe.
The VS Code extension ships from the editors/vscode-cellscript submodule with grammar, snippets, hover, completion, and validation coverage for the new syntax, still delegating semantic decisions to cellc. cellscript-mcp remains a read-only compiler/documentation interface — not a second compiler or deployment client. And the website’s provenance and assurance snapshots are regenerated from the 0.22 compiler output; they no longer show stale 0.17 versions.
4. New CKB helpers, with explicit trust boundaries
New runtime helpers land this cycle, each with a deliberately narrow, documented scope:
- Exact-index and literal-bounded resolved-CellDep data-hash checks. The bounded scan accepts only a literal maximum in
1..=64, uses the realLOAD_CELL_BY_FIELD(DATA_HASH)syscall path, stops onINDEX_OUT_OF_BOUND, and fails with stable runtime code63when absent. CKB-VM sees resolved CellDeps; out points, dep types, and original DepGroup identity remain builder or manifest evidence. - Fixed-width SHA-256 and SHA256d for 32-byte values and 64-byte pairs, plus a SHA256d Merkle verifier bounded to 16 siblings. Rust reference vectors and positive/negative CKB-VM tests cover the generated RISC-V. This is explicitly not a Bitcoin SPV implementation.
verifier::btc::bip340::require_signature_from_cell_depfor an explicit literal CellDep index (the index-0 spelling is retained for compatibility), with a fixed 144-byte VM2 IPC envelope. It verifies only the supplied prehash. The caller still owns message-domain construction, ScriptGroup/WitnessArgs and sighash selection, key authority, replay policy, deployment pinning, and external verifier review.
See the signature verifier ABI.
5. Bundled contracts now model real Cell identities and asset settlement
The examples stopped treating identifiers or witness values as settlement:
- AMM pools bind both token TypeHashes and derive initial LP supply geometrically;
- NFT sales consume and relock typed Token payments;
- timelocks and atomic swaps release actual Token outputs;
- DAO votes lock and redeem voting Tokens;
- vesting declares an
Active -> Activeself-loop for repeatable partial claims, withActive -> FullyClaimedas the terminal transition; - field-preserving N-input/N-output resource permutations are checked as runtime conservation — closing the strict ProofPlan gap for NFT royalty/seller payment pairs without action-name-specific backend rules.
The bundled multisig.cell example now says what it actually proves. Its Approval records are explicitly non-cryptographic; discarded 64-byte signature payloads are gone; witness time is labelled as reported rather than chain time; and real signer authentication, sighash binding, WitnessArgs layout, replay policy, and verification belong in an explicit Lock Script or pinned verifier package. The README no longer describes nonexistent CKB signature syscalls. The production example matrix is now 43 business actions and 17 locks, and pure AMM helpers are no longer exposed as transaction entries.
6. Fiber, Spore, and RGB++ — narrow scopes, honestly labelled
Three ecosystem paths land this cycle, each inside a deliberately narrow boundary:
- Fiber. The new
cellscript-fiber-adaptercrate derives a dedicatedfungible-type-group-v1artifact and native Fiber UDT configuration from compiler, deployment, live-Cell, and node evidence — without a Fiber profile or afiber-libdependency. The executable boundary is narrow: exact 16-byte little-endianu128data, full Type Script group conservation, closed issuance/destruction authority formats, and rejection of unauthorised mint/burn while ignoring Fiber’s xUDT-compatible witness prefix. Bounded local-devnet runs covered Fiber’s official multi-hop UDT payment and pending-TLC watchtower force-close collections. The clean, pinned full lifecycle/negative matrix is still pending, so this is not a production-readiness claim. Multi-asset packages select one structurally eligible asset withcellscript-fiber ... --asset <Type>. See the Fiber operator guide. - Spore and RGB++. Compile-checked identity-adapter packages under
examples/ecosystem/bind exact CKB Script identities and transaction positions while deliberately leaving Spore rules, RGB++ commitments, Bitcoin validation, witnesses, confirmations, and orchestration to pinned protocol packages and builders. See the interop boundary guide.
Try it
NOTE
CellScript 0.22 currentyly does not claim production Fiber readiness without the pinned external lifecycle matrix, builder/capacity/tx-pool/commit/live-chain evidence from compiler-only ProofPlan tiers, dynamic/recursive/generic payload ADTs, unbounded collection iteration, transaction-view reads inside type validity predicates, consensus-checked TemplateLayout commitments, canonical AST/IR receipt hashes, or production Spore/RGB++/Bitcoin-SPV/external-BIP340-verifier assurance without their pinned packages and independent evidence.
If something regresses, open an issue or post on the Nervos Talk thread.
