Skip to content

Repository files navigation

OffCKB

npm CI npm npm node

CKB local development network for your first try.

  • One-line command to start a devnet, no docker required
  • Pre-funded test accounts
  • Built-in scripts like CKB-JS-VM and Spore-contract
  • Create boilerplate to build CKB Smart Contract in Typescript
  • Proxy RPC that automatically dumps failed transactions for easier debugging

Migrate from v0.3.x to v0.4.x:

There are BREAKING CHANGES between v0.3.x and v0.4.x, make sure to read the migration guide before upgrading.


Install

npm install -g @offckb/cli

or use pnpm to install:

pnpm install -g @offckb/cli

Require Node version >= v20.0.0. We recommend using latest LTS version of Node to run offckb

Note for Windows users: If installation fails due to native module compilation issues, the CLI will still work but may use portable binaries instead of optimized ones. For better performance, consider installing Visual Studio Build Tools.

Usage

Usage: offckb [options] [command]

ckb development network for your first try

Options:
  -V, --version                                 output the version number
  --json                                        Output one command result as JSON on stdout and logs as NDJSON on stderr
  -h, --help                                    display help for command

Commands:
  node [CKB-Version]                            Use the CKB to start devnet
  node stop                                     Stop the running CKB devnet daemon
  fiber start [FNN-Version]                     Start Fiber (FNN) nodes on the running devnet CKB
  fiber stop                                    Stop the daemon-managed fiber nodes
  fiber status                                  Show the status of the local CKB and all fiber nodes
  fiber logs --node <id>                        Show the log of a fiber node
  fiber clean                                   Clean the fiber environment
  create [options] [project-name]               Create a new CKB Smart Contract project in JavaScript.
  deploy [options]                              Deploy contracts to different networks, only supports devnet and testnet
  debug [options]                               Quickly debug transaction with tx-hash
  system-scripts [options]                      Print/Output system scripts of the CKB blockchain
  clean                                         Clean the devnet data, need to stop running the chain first
  accounts                                      Print account list info
  deposit [options] [toAddress] [amountInCKB]   Deposit CKB tokens to address, only devnet and testnet
  transfer [options] [toAddress] [amountInCKB]  Transfer CKB tokens to address, only devnet and testnet
  transfer-all [options] [toAddress]            Transfer All CKB tokens to address, only devnet and testnet
  balance [options] [toAddress]                 Check account balance, only devnet and testnet
  install <tool>                                Install a tool binary used by offckb (e.g. the native ckb-debugger)
  debugger                                      Port of the raw CKB Standalone Debugger
  status [options]                              Show ckb-tui status interface
  logs [options] [target]                       Show devnet logs: node (default), contract script debug output, miner, or RPC proxy events
  config <action> [item] [value]                do a configuration action
  devnet config                                 Edit devnet configuration
  devnet info                                   Show fork metadata and node/indexer readiness
  devnet fork [options]                         Fork Mainnet/Testnet state into the local devnet
  help [command]                                display help for command

Use offckb [command] -h to learn more about a specific command.

Get started

1. Run a Local CKB Devnet {#running-ckb}

Start a local blockchain with one command:

offckb node

Specify a CKB version:

offckb node 0.201.0

Or set a default version globally:

offckb config set ckb-version 0.201.0
offckb node

Or specify the path to your locally compiled CKB binary:

offckb node --binary-path /path/to/your/ckb/binary

When using --binary-path, it will ignore the specified version and network, and only work for devnet.

Run in Daemon Mode

Start the devnet in the background so your terminal stays free:

offckb node --daemon

The daemon writes its logs and PID to the devnet data folder, for example:

  • Logs: ~/Library/Application Support/offckb-nodejs/devnet/data/logs/daemon.log
  • PID file: ~/Library/Application Support/offckb-nodejs/devnet/data/logs/daemon.pid

Stop the daemon later with:

offckb node stop

If a fiber environment is running in a foreground terminal, node stop refuses rather than orphaning its FNNs on a stopped chain — stop them there first, or pass offckb node stop --force to stop CKB anyway (the FNNs keep running).

View Logs

A foreground offckb node stays quiet by default: it prints lifecycle events, contract script debug output (debug! in your scripts), submitted transaction hashes, and RPC errors. The node, miner, and RPC proxy always write full logs to files under the devnet data folder, and offckb logs reads them in any run mode (foreground, daemon, or while offckb status is attached):

offckb logs                # node log (default)
offckb logs script         # contract script debug output only
offckb logs miner          # miner log
offckb logs rpc            # RPC requests, transaction hashes, RPC errors
offckb logs -f             # stream new lines, tail -f style
offckb logs --tail 200 --grep ERROR

Use offckb node --verbose to restore the old behavior of printing the full raw node/miner output to the terminal.

Agent-Friendly JSON Output

For programmatic consumption or agent integration, add --json before or after the command:

offckb --json balance ckt1...
offckb devnet info --json

In JSON mode, stdout is reserved for one stable command result. Progress logs are newline-delimited JSON on stderr, and failures use { "ok": false, "code", "message" } with a non-zero exit code. This lets scripts parse stdout without scraping log messages or stack traces:

{ "ok": true, "command": "balance", "network": "devnet", "address": "ckt1...", "ckb": "4200", "udt": [] }

RPC & Proxy RPC

When the Devnet starts:

The proxy RPC server forwards all requests to the RPC server and record every requests while automatically dumping failed transactions for easier debugging.

You can also start a proxy RPC server for public networks:

offckb node --network <testnet or mainnet>

Using a proxy RPC server for Testnet/Mainnet is especially helpful for debugging transactions, since failed transactions are dumped automatically.

Watch Network with TUI

Once you start the CKB Node, launch the interactive CKB-TUI for one network:

offckb status --network devnet
offckb status --network testnet
offckb status --network mainnet

status performs a JSON-RPC health check through the proxy before opening the TUI and requires an interactive terminal.

The TUI's system-metric panels are powered by CKB's Terminal RPC module, which requires CKB >= 0.205.0. If you run the devnet with an older CKB (e.g. offckb node 0.120.0 or --binary-path pointing at an old build), offckb starts the node without that module and those panels will be unavailable; upgrade CKB to get them.

2. Create a New Contract Project {#create-project}

Generate a ready-to-use smart-contract project in JS/TS using templates:

offckb create <your-project-name> -c <your-contract-name>
  • The -c option is optional, if not provided, the contract name defaults to hello-world.

Note for Windows Users:

The generated project uses ckb-testtool with the WASM debugger by default, which works on all platforms. To run mock tests with the native debugger instead (for example, while debugging upstream WASM issues), install ckb-debugger once with offckb:

offckb install ckb-debugger

This downloads the prebuilt ckb-debugger binary for your platform from the official ckb-standalone-debugger releases and puts a ckb-debugger shim next to the offckb binary so it is available on PATH.

Then disable the WASM debugger in your mock test file:

  1. Open the mock test file (e.g., <your-contract-name>.mock.test.ts)
  2. Comment out or delete the verifier.setWasmDebuggerEnabled(true) line:
    // When using native ckb-debugger, comment out or delete the following line:
    // verifier.setWasmDebuggerEnabled(true);

After completing these steps, npm run test should pass without mock test failures.

offckb create installs ckb-debugger for you automatically when it is missing.

3. Deploy Your Contract {#deploy-contract}

offckb deploy --network <devnet/testnet> --target <path-to-your-contract-binary-file-or-folder> --output <output-folder-path>
  • Deployment info is written to the output-folder-path you specify.

Upgradable Scripts with --type-id Pass the --type-id option if you want your Scripts to be upgradable:

offckb deploy --type-id --network <devnet/testnet>
  • Important: Upgrades are keyed by the contract‘s artifact name.
    • If you plan to upgrade with --type-id, do not rename your contract artifact (e.g. keep hello-world.bc).
    • Renaming it makes the offckb unable to find the previous Type ID info from the output-folder-path and will create a new Type ID.

4. Debug Your Contract {#debug-contract}

When you interact with the CKB Devnet through the Proxy RPC server (localhost:28114), any failed transactions are automatically dumped and recorded for debugging.

Debug a Transaction:

offckb debug --tx-hash <transaction-hash> --network <devnet/testnet>

output example:

offckb debug --tx-hash 0x64c936ee78107450d49e57b7453dce9031ce68b056b2f1cdad5c2218ab7232ad
Dump transaction successfully

******************************
****** Input[0].Lock ******

hello, this is new add!
Hashed 1148 bytes in sighash_all
sighash_all = 5d9b2340738ee28729fc74eba35e6ef969878354fe556bd89d5b6f62642f6e50
event = {"pubkey":"45c41f21e1cf715fa6d9ca20b8e002a574db7bb49e96ee89834c66dac5446b7a","tags":[["ckb_sighash_all","5d9b2340738ee28729fc74eba35e6ef969878354fe556bd89d5b6f62642f6e50"]],"created_at":1725339769,"kind":23334,"content":"Signing a CKB transaction\n\nIMPORTANT: Please verify the integrity and authenticity of connected Nostr client before signing this message\n","id":"90af298075ac878901282e23ce35b24e584b7727bc545e149fc259875a23a7aa","sig":"b505e7d5b643d2e6b1f0e5581221bbfe3c37f17534715e51eecf5ff97a2e1b828a3d767eb712555c78a8736e9085b4960458014fa171d5d169a1b267b186d2f3"}
verify_signature costs 3654 k cycles
Run result: 0
Total cycles consumed: 4013717(3.8M)
Transfer cycles: 44947(43.9K), running cycles: 3968770(3.8M)

******************************
****** Output[0].Type ******

verify_signature costs 3654 k cycles
Run result: 0
Total cycles consumed: 3916670(3.7M)
Transfer cycles: 43162(42.2K), running cycles: 3873508(3.7M)

Debug a Single Cell Script:

offckb debug <transaction-hash> --single-script <single-cell-script-option>

The single-cell-script-option format is <cell-type>[<cell-index>].<script-type>

  • cell-typeinput or output
  • cell-index → index of the Cell in the transaction
  • script-typelock or type

Example:

offckb debug --tx-hash <tx-hash> --single-script input[0].lock

All debug utilities are powered by ckb-debugger.

Install the Native ckb-debugger

offckb debug requires the native ckb-debugger binary. Install it once with:

offckb install ckb-debugger

This downloads the prebuilt binary for your platform from the official ckb-standalone-debugger releases (no Rust toolchain or compilation needed), verifies its checksum, and exposes it on PATH.

To uninstall, remove the binary under the offckb data directory (see offckb config list) and the ckb-debugger shim next to the offckb binary.

5. Explore Built-in Scripts {#explore-scripts}

Print all the predefined Scripts for the local blockchain:

offckb system-scripts --list

Export options:

  • Lumos format
offckb system-scripts --export-style lumos
  • CCC format:
offckb system-scripts --export-style ccc
  • Save to a JSON file:
offckb system-scripts --output <output-file-path>

6. Tweak Devnet Config {#tweak-devnet-config}

By default, OffCKB use a fixed Devnet config. You can customize it, for example by modifying the default log level (info,ckb-script=debug).

  1. Open the interactive Devnet config editor:
offckb devnet config

The editor uses a three-column layout: first-column file switcher (ckb.toml / ckb-miner.toml), a middle primary editing pane, and a smaller right read-only reference pane that shows the full built-in template for the currently selected file.

The left editing pane supports full key browsing/editing, including primitive value edits, object key add, array append/insert/move, search filter, and path delete.

Common shortcuts: Enter edit primitive, a add key/item, i insert array item, m move array item, d delete path, / search filter, n/N next/previous search match, c add custom value in fixed-array dialog (when allowed), s save, q quit.

Note: saving rewrites ckb.toml / ckb-miner.toml into canonical TOML format; upstream comments and original formatting are not preserved after save.

You can also update the same fields non-interactively (useful for scripts/CI):

offckb devnet config --set ckb.logger.filter=info
offckb devnet config --set ckb.rpc.enable_deprecated_rpc=true --set miner.client.poll_interval=1500

If your terminal is non-interactive (no TTY, e.g. CI/remote pipeline), use --set mode directly instead of the full-screen editor.

  1. Save changes and restart devnet:
offckb clean -d
offckb node
  1. (Advanced) Locate your Devnet config folder for manual edits:
offckb config list

Example result:

{
  "devnet": {
    "rpcUrl": "http://127.0.0.1:8114",
    "configPath": "~/Library/Application Support/offckb-nodejs/devnet",
    "dataPath": "~/Library/Application Support/offckb-nodejs/devnet/data"
  }
}

Pay attention to the devnet.configPath and devnet.dataPath.

  1. cd into the devnet.configPath . Modify the config files as needed. See Custom Devnet Setup and Configure CKB for details.
  2. After modifications, run offckb clean -d to remove the chain data if needed while keeping the updated config files.
  3. Restart local blockchain by running offckb node

7. Fork Mainnet/Testnet Into Your Devnet {#fork-devnet}

You can fork an existing Mainnet/Testnet data directory into your local devnet, so it keeps the real on-chain state (deployed contracts, cells) while mining locally with Dummy PoW. This implements the same flow as Devnet From Existing Data.

# Point at the directory used by the source node's `ckb -C`:
offckb devnet fork --from /path/to/ckb-data --dry-run
offckb devnet fork --from /path/to/ckb-data
offckb node --daemon
offckb devnet info
  • Database fork mode requires --from; it points at the directory the source node runs with (ckb -C), which must contain data/db. Keeping the source explicit makes large database copies predictable in local scripts and CI.
  • Stop the source node first. Use --dry-run to validate the source chain, CKB/DB compatibility, migration requirement, and target without replacing the current devnet.
  • The source chain is auto-detected from the source ckb.toml; pass --source mainnet|testnet when it cannot be detected, and --spec-file <path> to use a local chain spec (e.g. offline).
  • The command copies the chain state (your original data is never modified), deliberately excludes peer store/log/tmp data, imports the matching chain spec, patches it for local mining, verifies the genesis hash, and writes a fork receipt.
  • Fork networking is outbound-isolated: no bootnodes, persisted peers, peer discovery, or outbound peer slots. offckb devnet info displays the observed peer count so this property is visible.
  • If ckb migrate --check says the database is old, the preflight stops before changing the devnet. Re-run with --migrate; only the copied database is migrated.
  • The first offckb node run automatically boots with --skip-spec-check --overwrite-spec; later runs are normal. Daemon startup waits for healthy CKB RPC, miner spawn, and proxy health before reporting success.
  • Forking replaces the current devnet; use --force to replace an existing devnet/fork, or offckb clean to reset back to a pure devnet.

offckb devnet info reports RPC readiness, node tip, Indexer tip/lag, peer count, network isolation, and fork metadata. Balance and signing commands warn while the Indexer is unavailable or behind instead of silently presenting incomplete state.

On a forked devnet, offckb system-scripts, transfers, deploys and offckb debug --tx-hash <hash> work against the real source-chain state, e.g. debugging a failed mainnet transaction fully locally.

Caution

CKB transactions carry no chain id, so a transaction built on a mainnet fork that spends copied mainnet cells is also valid on mainnet (CKB provides no replay protection). offckb's own flows only use dev keys and fork-mined cells, which cannot replay. Never sign transactions with real mainnet keys against a fork unless you intend to broadcast them yourself.

offckb transfer fails closed on a Mainnet fork: non-built-in keys require --allow-external-key-on-mainnet-fork, and inputs copied from Mainnet are rejected even with that override. (--allow-mainnet-replay-risk from 0.4.9 remains as a deprecated alias.)

8. Run a Fiber Devnet {#fiber-devnet}

OffCKB can start and manage a local Fiber development environment on top of the devnet: the Fiber contracts (auth, funding_lock, commitment_lock) live in the local chain's genesis block, and each FNN node gets its own CKB account, network identity, ports, data and log file.

# Start CKB, miner, RPC proxy and 2 FNN nodes in one command
offckb node --fiber

# Or start only the FNN nodes on an already-running devnet
offckb node
offckb fiber start

# Background mode
offckb node --fiber --daemon      # one manager for CKB + FNNs, stopped by `offckb node stop`
offckb fiber start --daemon       # separate fiber manager, stopped by `offckb fiber stop`

# Inspect
offckb fiber status [--json]
offckb fiber logs --node 1 [-f]

# Clean up
offckb fiber clean --data         # delete only the FNN stores (channels/payments)
offckb fiber clean                # delete the whole fiber environment
  • Only the plain local devnet is supported: no mainnet/testnet, and no forked devnet (a fork.json present in the devnet directory rejects Fiber startup).
  • A devnet created by an offckb version without Fiber support does not have the Fiber contracts in its genesis. fiber start / node --fiber on such a devnet refuse with migration guidance: rebuild with offckb clean (which deletes the local chain data) and start again; a plain offckb node keeps working on the old devnet unchanged.
  • Node N uses built-in CKB account N+2 (accounts 3-18 are reserved for Fiber), RPC port 21713+N and P2P port 8343+N. Up to 16 nodes: offckb fiber start --nodes 4.
  • offckb fiber start [FNN-Version] downloads a tested FNN release (currently 0.9.0). Downloaded tarballs are verified against SHA-256 digests pinned in offckb before installation. Use --binary-path <fnn> (or --fnn-binary-path <fnn> with node --fiber) to run a locally built FNN.
  • Every FNN writes its stdout/stderr to devnet/fiber/nodes/<id>/fnn.log, never to your terminal. Per-node FNN config overrides live in devnet/fiber/nodes.yml (regenerated config.yml files do not keep hand edits). Fields owned by offckb — chain, scripts, listening/bootnode addresses, store path, CKB RPC/UDT wiring, services — are managed and cannot be overridden there.
  • Startup verifies that the devnet spec, the running CKB and every FNN agree on the same chain (genesis hash), and checks each node's identity key, CKB account and available balance before reporting ready.
  • One fiber environment per machine: the RPC/P2P ports are fixed per node id, so a second concurrent fiber environment fails its port check. Note the CKB side of the check is the chain's genesis hash, and every plain offckb devnet shares the same genesis — if you run several offckb environments on one machine (e.g. separate XDG_DATA_HOME), make sure fiber start attaches to the CKB you actually started for it; when in doubt, check offckb fiber status against the environment you mean to use.
  • UDT channels: the FNN config whitelists the devnet sUDT and xUDT issued by built-in account 19, so issue test UDTs from that account (offckb udt issue ... --privkey-file with account 19's key) to the node accounts before opening UDT channels. A few things that differ from plain CKB channels:
    • offckb udt issue <amount> takes the amount in the token's base unit (no 10^8 conversion): 3000 issues 0.00003 sUDT at 8 decimals, so issue generously before funding a channel.
    • Both sides of a UDT channel must hold the UDT. The accepting node needs its own UDT cells — otherwise accept_channel fails with "can not find enough UDT owner cells" — so issue the UDT to both node accounts first.
    • UDT channels are not auto-accepted (CKB channels are). After open_channel the peer stays in NegotiatingFunding until you call accept_channel on the peer node, and its funding_amount must be 0x0 — a nonzero amount fails with "invalid funding tx".

Config Setting

List All Settings

offckb config list

Set CKB version

offckb config get ckb-version
> 0.113.0
offckb config set ckb-version 0.117.0
offckb config get ckb-version
> 0.117.0

Set Network Proxy

offckb config set proxy http://127.0.0.1:1086
> save new settings
offckb config get proxy
> http://127.0.0.1:1086
offckb config rm proxy
> save new settings
offckb config get proxy
> No Proxy.

Log-Level

You can tweak env LOG_LEVEL to control the offckb log level.

For example, set LOG_LEVEL=debug gives you more outputs of offckb proxy RPC.

LOG_LEVEL=debug offckb node

Built-in scripts

Accounts

On a pure OffCKB devnet, OffCKB comes with 20 pre-funded accounts, each initialized with 42_000_000_00000000 capacity in the genesis block. A fork keeps the source chain genesis and therefore has no OffCKB genesis allocation; built-in dev accounts are funded by locally mined cellbase cells instead.

offckb accounts
offckb accounts --show-private-keys  # trusted local terminals only

On a Mainnet fork, accounts re-encodes the same dev lock scripts with the ckb address prefix. Once the Indexer is caught up it also reports each account's spendable pure-CKB balance; until then the field is omitted with a warning. Private keys are hidden by default so JSON and agent logs do not collect them.

  • All private keys are stored in the account/keys file.
  • Detailed information for each account is recorded in account/account.json.
  • When deploying contracts, the deployment cost are automatically deducted from these pre-funded accounts. This allows you to test deployments without faucets or manual funding.

For commands that accept a private key, prefer --privkey-file <path> or OFFCKB_PRIVATE_KEY over --privkey, which is visible in shell history and process listings.

⚠️ DO NOT SEND REAL ASSETS TO THESE ACCOUNTS. THE KEYS ARE PUBLIC, AND YOU MAY LOSE YOUR MONEY ⚠️

About CCC

offckb uses CCC as the development framework to build the CKB dApp template projects.

FAQ

Sometimes you might encounter sudo permission problems. Granting the current user write access to the node_modules directory can resolve the problem.

sudo chown -R $(whoami) /usr/local/lib/node_modules
npm install -g @offckb/cli

Contributing

check development doc

About

CKB local development network for your first try.

Topics

Resources

Stars

16 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages