Write the transaction you expect. Ship the cell you can prove.

Describe CKB contracts as readable state changes. The compiler checks them, lowers them to on-chain artifacts, and keeps the metadata reviewers need — all from one source.

token.cell
1module cellscript::fungible_token2// ... invariant and MintAuthority omitted3resource Token has store, create, consume, replace, burn, relock {4    amount: u64,5    symbol: [u8; 8],6}78action transfer_token(token: Token, to: Address) -> next_token: Token {9    verification10        consume token11        create next_token = Token { amount: token.amount, symbol: token.symbol } with_lock(to)12}1314action burn(token: Token) {15    verification16        require token.amount > 0, "cannot burn zero"17        destroy token18}
1module cellscript::nft2// ... constants and Metadata struct omitted3resource NFT has store, create, consume, replace, burn, relock, read_ref {4    token_id: u64,5    owner: Address,6    metadata_hash: Hash,7    royalty_recipient: Address,8    royalty_bps: u16,9}1011// ... listing and offer receipts omitted12action transfer(nft_before: NFT, to: Address) -> nft_after: NFT {13    transition nft_before -> nft_after14    verification15        require nft_before.owner != to, "Cannot transfer to self"16        preserve nft_after from nft_before {17            token_id18            metadata_hash19            royalty_recipient20            royalty_bps21        }22        require nft_after.owner == to23}
1module cellscript::amm_pool2use cellscript::fungible_token::Token3// ... LPReceipt omitted4shared Pool has store, create, replace {5    token_a_symbol: [u8; 8],6    token_b_symbol: [u8; 8],7    reserve_a: u64,8    reserve_b: u64,9    total_lp: u64,10    fee_rate_bps: u16,11}1213action swap_a_for_b(pool_before: Pool, input: Token, min_output: u64, to: Address) -> (pool_after: Pool, token_out: Token) {14    transition pool_before -> pool_after15    verification16        require input.symbol == pool_before.token_a_symbol, "wrong input token"17        let fee = input.amount * pool_before.fee_rate_bps as u64 / 1000018        let net_input = input.amount - fee19        let amount_out = pool_before.reserve_b * net_input / (pool_before.reserve_a + net_input)20        // ... preserve, require, consume, create omitted21        require amount_out >= min_output, "slippage exceeded"22}
1module cellscript::vesting2use cellscript::fungible_token::Token3// ... VestingConfig and VestingGrant fields omitted4flow VestingGrant.state {5    Granted -> Claimable;6    Granted -> FullyClaimed;7    Claimable -> FullyClaimed;8}910action claim_vested(grant: VestingGrant) -> (tokens: Token, updated_grant: VestingGrant) {11    transition grant.state: Claimable -> updated_grant.state: FullyClaimed12    verification13        let now = env::current_timepoint()14        require now >= grant.cliff_timepoint, "cliff not reached"15        // ... vesting arithmetic omitted16        consume grant17        create tokens = Token { amount: claimable, symbol: grant.token_symbol } with_lock(grant.beneficiary)18}
$cellc examples/token.cell --target-profile ckb

Why developers use it

CellScript is for teams that want CKB contract intent to stay readable while iteration stays fast enough to keep editing in flow.

State changes are explicit

Actions say which Cells are consumed, created, replaced, burned, or relocked, so reviewers can follow transaction shape.

Compiler checks catch drift

Type, lifecycle, policy, and target checks run before generated code reaches a builder, deployment process, or VM harness.

Build evidence is inspectable

The compiler emits metadata for actions, types, hashes, effects, and CKB warnings that tools and reviewers can read.

From .cell to CKB code

The homepage keeps the pipeline high level. Detailed language concepts, generated metadata, and registry policy belong in Docs and Registry flows.

Write .cell source

Define Cell data, locks, and allowed transaction actions.

Check the rules

Catch invalid fields, state changes, and Cell lifecycles early.

Record review facts

Write JSON for actions, types, hashes, and policy checks.

Generate CKB instructions

Turn the checked model into ckb-vm RISC-V code.

Write the artefact

Produce assembly or ELF plus matching metadata.

Try the contract shapes

The Playground opens real example sources and compiles them in the browser. Test the contract shape first, then move to local CKB target builds.

Try it locally

Use the local compiler when you want the fast path from source to CKB target output plus inspectable metadata.

1

Install

cargo install --path .

2

Compile

cellc examples/token.cell --target riscv64-elf --target-profile ckb

3

Check

cellc check --target-profile ckb