Repository navigation
Description
Summary
Design a CKB-native source and metadata model for typed transaction roles across independently compiled Scripts.
The goal is to let one CellScript entry declare the foreign inputs, outputs, dependencies, and peer Script identities that it relies on in the same atomic CKB transaction—without adding an ELF linker, runtime calls, or a shared hidden state model.
This work should begin only after the artifact-only composition boundary in #9 is specified well enough to expose real role and conflict requirements.
Problem
CellScript can already:
- inspect transaction and Script Group views through typed
SourceView; - construct and compare
Script/ScriptRefvalues; - import schemas and pure helpers at compile time;
- bind package interfaces and deployment identities;
- express explicit local input/output transitions.
What it cannot express as one typed protocol contract is:
“This action is valid only when a foreign Script consumes these typed inputs, creates these typed outputs, and independently accepts the same transaction under this exact or compatible identity.”
Applications can hand-code individual syscall checks, but the relationship is not a first-class role graph. It is therefore missing from interface compatibility, builder generation, ProofPlan, audit output, and protocol-level transaction composition.
Argent's closed/open ICC and consumes/emits/observes model demonstrate the product value of making the application graph source-level. CellScript must adapt the idea to CKB's Cell Model and Script Groups rather than copying Kaspa covenant semantics.
CKB-native model
CKB already executes independent Lock and Type Script Groups against the same transaction. The language feature should describe and verify relationships between those groups; it should not call one Script from another.
flowchart TB
SRC["CellScript protocol/role declarations"] --> A["Compile artifact A obligations"]
SRC --> B["Compile artifact B obligations"]
SRC --> PB["Emit ProtocolBundle role graph"]
TX["One atomic CKB transaction"] --> GA["Script Group A"]
TX --> GB["Script Group B"]
GA --> VA["Artifact A validates its observable facts"]
GB --> VB["Artifact B validates its observable facts"]
VA --> OK{"Both independently accept?"}
VB --> OK
OK -- "yes" --> ACCEPT["Transaction valid"]
OK -- "no" --> REJECT["Transaction rejected"]
Required role classes
The design should separate these concepts rather than overloading ordinary action parameters:
Local lifecycle roles
- inputs controlled by the current Script Group;
- outputs created or updated under the current Script identity;
- existing
consume,create,transition, and bounded lifecycle rules.
Closed foreign roles
A peer role bound to:
- exact package/interface hash;
- exact serialized state schema;
- exact deployment and Script identity policy;
- fixed Lock/Type role;
- explicit transaction or group source;
- fixed or bounded cardinality.
This is the CKB analogue of a statically linked peer application, but it remains an independently executed Script.
Open foreign roles
A peer role whose implementation is chosen at transaction construction time, subject to an explicit interface/schema/effect contract and an on-chain-verifiable Script identity binding.
Open roles must not rely on a Registry lookup as consensus proof. See the separate interface-bound Script-handle issue that will build on this role model.
Dependency roles
- code or data CellDeps;
- HeaderDeps;
- spawned VM/IPC verifier contracts;
- read-only configuration Cells.
Dependency roles remain distinct from consumed inputs and created outputs.
Possible source shape
This issue must not preselect final syntax. A strawman only illustrates the semantic information:
protocol Settlement {
closed input order_before: OrderState
from transaction
script order_v1
open input asset_before: FungibleAsset
interface fungible_v1
output order_after: OrderState
verified_by order_v1
output asset_after: FungibleAsset
same_implementation_as asset_before
}
action settle(...) for Settlement {
transition order_before -> order_after
verification
require asset_after.amount == asset_before.amount
}
The accepted design may use a manifest rather than new language syntax. The non-negotiable part is the typed role graph and its evidence, not the spelling.
Role graph and obligations
graph LR
ENTRY["Current entry"] --> LI["Local input role"]
ENTRY --> LO["Local output role"]
ENTRY --> FI["Foreign input role"]
ENTRY --> FO["Foreign output role"]
ENTRY --> DEP["CellDep/HeaderDep role"]
FI --> ID["Script/interface identity"]
FI --> SCHEMA["Typed schema decode"]
FO --> CORR["Output correspondence"]
FO --> PEER["Peer independently executes"]
DEP --> POLICY["Read-only identity policy"]
For each role, metadata must record:
- stable role identity and source span;
- local/foreign/dependency classification;
- transaction versus group-relative source;
- cardinality;
- Lock/Type/CellDep role;
- Script and deployment identity policy;
- interface and schema requirements;
- readable fields and required relations;
- whether the current Script checks the fact on chain;
- which peer artifact independently enforces its own transition;
- builder assumptions that remain off chain.
Soundness rules
- Presence is not authorization. Observing a peer input proves only that it is present and matches the declared identity.
- Shape is not behavior. Decoding a peer state does not prove that the peer intended the observer's transition.
- Builder construction is not consensus proof. Every claimed on-chain fact needs generated verifier coverage.
- Peer success is independent. The bundle must execute each participating Script Group; one Script cannot claim another has accepted without evidence.
- Closed and open roles cannot collapse. An exact implementation dependency must not silently become an open interface slot.
- Transaction-wide sources are explicit. A role must not accidentally widen from Script Group to the complete transaction.
- Cardinality is executable. A bound in metadata is insufficient without runtime count enforcement.
- Interface identity must be bound. Package/Registry metadata alone cannot identify the Script bytes executing on chain.
Implementation phases
Phase 0 — use cases and threat model
Select at least three concrete multi-Script protocols, for example:
- token/order atomic settlement;
- factory/child Type ID launch;
- DAO proposal plus authorization Lock;
- shared pool plus independent token Type Scripts.
For each, document current manual checks and the intended role graph.
Phase 1 — metadata-only role graph
- add a versioned role schema to metadata and package interfaces;
- emit builder and ProofPlan requirements;
- integrate with [Architecture][Builder] Add an artifact-only multi-Script ProtocolBundle #9;
- make every unsupported executable claim remain explicitly metadata-only or fail-closed.
This phase must not advertise on-chain coverage.
Phase 2 — closed roles
- bind exact peer artifacts, interfaces, schemas, deployments, and Scripts;
- generate current-Script observation checks;
- construct and dry-run all peer Script Groups through ProtocolBundle;
- add negative fixtures for identity, source, cardinality, schema, and output mismatches.
Phase 3 — open roles
- add only after the interface-bound Script handle has a complete consensus binding;
- preserve exact runtime-selected implementation across declared continuations;
- ensure both observer and peer independently validate the transaction;
- add substitution, downgrade, and Registry-spoofing adversarial tests.
Acceptance criteria
- An accepted RFC defines local, closed foreign, open foreign, and dependency roles.
- At least three real protocol fixtures justify the model.
- Roles are canonical metadata and public-interface entries.
- Every claimed check maps to typed semantics, ProofPlan, lowering, and machine evidence.
- ProtocolBundle builds and dry-runs every participating Script Group against identical transaction bytes.
- Closed roles bind exact interface, deployment, and Script identities.
- Open roles cannot ship before an on-chain-verifiable interface-handle contract exists.
- Transaction versus Script Group scope is explicit and tested.
- Fixed and bounded cardinality rules are executable.
- Negative tests cover missing, extra, reordered, substituted, incompatible, and non-executed peer roles.
- Generated builder, CLI, LSP, VS Code, Registry, checker, and docs agree.
- No ELF-linker or cross-Script-call claim is introduced.
Non-goals
- synchronous contract calls;
- shared mutable VM memory;
- compiling several Scripts into one ELF;
- Kaspa covenant IDs or P2SH template receipts;
- trusting Registry availability during consensus execution;
- inferring peer behavior from matching state shape;
- adding actor/mailbox terminology to CellScript;
- hiding transaction roles behind ordinary generic values.
Dependencies
- [Architecture][Builder] Add an artifact-only multi-Script ProtocolBundle #9 — artifact-only ProtocolBundle.
- [Candidate][Consensus runtime] Implement executable bounded Cell-group consumption #7 and [Candidate][Consensus runtime] Implement executable bounded output-plan correspondence #8 — executable bounded cardinality when a role is not fixed-arity.
- Interface-bound runtime Script handles should be specified separately and consumed by the open-role phase.
Activity
a19q3 commentedon Aug 27, 2026
Research update: Argent ICC confirms the model, but also sharpens what one CKB Script can claim
Comment audit
There were no prior comments on this issue at the time of review.
The relevant Argent PRs have little substantive review discussion. The most useful primary source is the repository's explicit ICC semantics document:
https://github.com/argent-lang/argent/blob/6a627da4abdd53e71fdb71da0f711ccc96424eb6/docs/icc-semantics.md
It states two rules that should be normative here:
CKB-specific interpretation
CKB already provides the atomic composition mechanism: the node groups inputs and outputs by exact Script and executes each relevant Lock/Type Script Group against the same transaction.
Therefore a CellScript role declaration can prove only facts observable and checked by the current artifact, such as:
It cannot, from inside the current CKB-VM program, call a syscall that says “peer artifact B has accepted.” Peer success is a property of whole-transaction validation. ProtocolBundle can dry-run and record every group off chain; CKB consensus makes the transaction valid only if all groups pass on chain.
Metadata should therefore distinguish:
Do not collapse these into one verified boolean.
Closed versus open roles
Argent's closed/open split remains useful:
The audit supports shipping closed roles first. Open roles must wait for #11 because a raw CKB Script and a Registry interface name do not prove that the executing code satisfies that interface.
For a closed role, exact identity should include at least:
Presence, observation, and authorization
A useful role taxonomy is:
This prevents an observed foreign Cell from accidentally acquiring consume/create authority in the type system.
Source qualification is mandatory
The official CKB source model distinguishes Input, Output, CellDep, HeaderDep, GroupInput, and GroupOutput:
https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0046-syscalls-summary/0046-syscalls-summary.md
Every role must preserve that distinction through AST, IR, typed semantics, ProofPlan, ABI, builder, and checker. “Input role” is not precise enough because transaction Input and GroupInput have different authority/visibility implications.
Recommended staging
Acceptance additions
Conclusion
The issue's direction is sound. The most important clarification is evidence attribution: typed roles describe relationships across independently executed Script Groups, while each generated artifact may claim only the checks it performs. Whole-transaction acceptance belongs to CKB consensus and ProtocolBundle evidence, not to a fictional cross-Script call.
a19q3 commentedon Sep 11, 2026
Completed for the exact closed-role 0.30 scope in
ee6dbfb4and exercised by the exact four-artifact ProtocolBundle/CKB-VM corpus througha2ee77aa. Closed roles bind source, schema, interface, artifact, deployment, Script identity, ownership, and evidence attribution without claiming runtime linkage between peer Scripts. Runtime-selected open roles have been split into post-v1 issue #29, dependent on compatible-open handle issue #28. Ledger/docs record the split andremaining_work=[]atcdc5b53c. No TAC or release workflow was invoked.