How to Deploy a Private Registry
For a step-by-step tutorial with visible results at each step, see Get started: registry operator.
This page covers the full deployment with all options and explains how each component connects to the others.
Deploy contracts
Section titled “Deploy contracts”./scripts/deploy.sh \ --network testnet \ --rpc-url https://testnet.ckb.dev \ --from-address <YOUR_CKT1_ADDRESS> \ [--no-build] # skip cargo build if binaries are fresh [--dry-run] # generate txs without signingOutputs:
deploy/info.json— deployment metadata, Type IDs, tx hashesdeploy/migrations/— migration files forckb-cli deploy apply-txs
To reuse the community contract binaries without redeploying, use the community Type IDs directly and skip this step. Your registry will have a unique type_id_value from your bootstrap transaction regardless.
Bootstrap the registry and treasury
Section titled “Bootstrap the registry and treasury”The bootstrap creates both the registry cell and the treasury seed in a single transaction. Run:
node scripts/build_treasury_bootstrap_tx.mjs deploy/bootstrap-tx.jsonThen sign and submit:
ckb-cli --url https://testnet.ckb.dev tx sign-inputs \ --tx-file deploy/bootstrap-tx.json \ --add-signatures
ckb-cli --url https://testnet.ckb.dev tx send \ --tx-file deploy/bootstrap-tx.jsonRecord the bootstrap transaction hash. This is the initial --registry-tx you pass to all CLI commands. As governance updates run, the registry cell moves — the current outpoint is auto-discovered via the indexer.
How the treasury connects to the registry
Section titled “How the treasury connects to the registry”The treasury-lock contract can only be spent when the transaction produces a valid proposal-anchor cell or returns capacity to itself. What “valid” means is encoded in the treasury-lock args:
treasury-lock args = governance_lock_type_id (32 bytes) | proposal_anchor_type_id (32 bytes)These must match the contracts you deployed in step 1. The bootstrap computes the treasury address from these IDs and embeds the full treasury lock script in the registry cell’s v3 governance header.
This means the CLI and GUI automatically discover the treasury address by reading the registry cell — no extra configuration is needed after bootstrap.
See How to deploy and seed the treasury for treasury management details.
Connect the CLI to your registry
Section titled “Connect the CLI to your registry”The CLI defaults to the canonical testnet registry. To use your private registry, pass flags to every governance command:
ckb-firewall propose ... --registry-tx <tx> --registry-index 0ckb-firewall anchor ... --registry-tx <tx> --registry-index 0ckb-firewall vote ... --registry-tx <tx> --registry-index 0ckb-firewall execute ... --registry-tx <tx> --registry-index 0ckb-firewall inspect ... --registry-tx <tx> --registry-index 0ckb-firewall check ... --registry-tx <tx> --registry-index 0Connect the GUI to your registry
Section titled “Connect the GUI to your registry”The GUI is started with:
ckb-firewall gui \ --registry-tx <bootstrap tx hash> \ --registry-index 0Connect the TypeScript SDK to your registry
Section titled “Connect the TypeScript SDK to your registry”Use RegistrySpecLike to find the live cell via the indexer, rather than hardcoding an outpoint:
import { findLiveRegistryCell } from "@ckb-firewall/sdk";
const registrySpec = { // The code hash of your deployed blacklist-registry contract // (from deploy/info.json under blacklist-registry.code_hash) codeHash: "<blacklist-registry code hash>", hashType: "type" as const, // The type_id_value printed by `ckb-firewall inspect` // or found in deploy/bootstrap-tx.json under registryCell.typeIdValue typeIdValue: "<your registry type_id_value>", required: true,};
const cell = await findLiveRegistryCell(rpcUrl, registrySpec);typeIdValue is the stable 32-byte identifier computed at bootstrap time. It never changes across governance updates, so you can embed it in your application and SDK configuration permanently.
If you are using the community contract binaries (not redeploying), use the community codeHash and only supply your own typeIdValue.
Run governance
Section titled “Run governance”See Step 4: Run a governance round for a complete worked example.
Configure the firewall lock
Section titled “Configure the firewall lock”See Step 5: Configure a firewall lock and How to build a firewall lock script.