Skip to content

Firewall Lock Args

The firewall lock args encode everything the on-chain lock needs to enforce blacklist checking: which registry cells to consult, which flags to apply, and which inner lock to delegate to once the check passes.

import { buildFirewallLockScript } from "@ckb-firewall/sdk";
import type { FirewallLockConfig } from "@ckb-firewall/sdk";
const config: FirewallLockConfig = {
firewallCodeHash: "0xabc...", // deployed firewall-lock code hash
firewallHashType: "type",
flags: 0x03, // check both lock_args and type_args
registries: [
{
codeHash: "0xdef...", // blacklist-registry code hash
hashType: "type",
typeIdValue: "0x123...", // 32-byte Type ID of the registry cell
required: true,
},
],
innerCodeHash: "0x9bd...", // secp256k1 lock code hash
innerHashType: "type",
innerArgs: "0x<20-byte-pubkey-hash>",
};
const lockScript = buildFirewallLockScript(config);
// { codeHash, hashType: "type", args: "0x<encoded v2 args>" }

All multi-byte integers are little-endian. Version 0x02 is the current on-chain format.

FieldSizeValue
version1 byte0x02
flags1 bytesee Flags
registry_count1 bytenumber of registry specs (0–255)
registry_specsregistry_count × 66 bytessee Registry spec
inner_code_hash32 bytescode hash of the inner lock script
inner_hash_type1 bytehash type of the inner lock (0x00=data, 0x01=type, 0x02=data1)
inner_args_len2 bytes u16byte length of inner_args
inner_argsinner_args_len bytesargs passed to the inner lock (e.g. 20-byte pubkey hash for secp256k1)

Minimum size (0 registries, 0-byte inner args): 1 + 1 + 1 + 32 + 1 + 2 = 38 bytes.

With 1 registry and a 20-byte secp256k1 pubkey hash: 38 + 66 + 20 = 124 bytes.

Each registry spec is exactly 66 bytes:

FieldOffset within specSizeValue
code_hash032 bytescode hash of the blacklist-registry type script
hash_type321 byte0x00=data, 0x01=type, 0x02=data1
type_id_value3332 bytesType ID of the specific registry instance (bytes 34–65 of the 66-byte registry type args)
required651 byte0x01 = transaction fails if this registry dep is absent; 0x00 = optional

The firewall lock matches a cell dep against a registry spec by comparing code_hash, hash_type, and dep.type.args[34..66] == type_id_value. This means the governance lock’s code hash (stored in registry type args bytes 1–33) can be upgraded without invalidating existing firewall lock configurations.

BitMeaning
0 (0x01)Check output lock_args against the blacklist
1 (0x02)Check output type_args against the blacklist
2–7Reserved — must be zero

Both bits set (0x03) is the recommended default. Setting flags = 0x00 is rejected on-chain with error UnsupportedFlags (code 7).

The v2 layout supports up to 255 registry specs in a single firewall lock. All required registries must be present as cell deps; the blacklist is the union of all active entries across all registries. If any required registry dep is missing the transaction fails with MissingRegistryCellDep (code 8).

const config: FirewallLockConfig = {
// ...
registries: [
{ codeHash: "0x...", hashType: "type", typeIdValue: "0x...", required: true },
{ codeHash: "0x...", hashType: "type", typeIdValue: "0x...", required: false },
],
};

Optional registries (required: false) are checked if present in the transaction’s cell deps but do not cause a failure if absent. Use them for supplementary watchlists that may not always be available.

After all blacklist checks pass, the firewall lock spawns the inner lock via spawn_cell. The inner lock’s argv receives:

  • argv[0] — hex-encoded inner args (e.g. the 20-byte pubkey hash)
  • argv[1] — hex-encoded secp256k1 signature (65 bytes) from WitnessArgs.lock

The inner lock is expected to verify the signature and exit 0 on success or any non-zero value on failure. The spawn-aware-secp256k1 contract is the canonical inner lock for standard secp256k1-blake160 wallets.

  • Builder (SDK): sdk/typescript/src/builder.tsbuildFirewallLockArgs, buildFirewallLockScript
  • Parser (Rust): contracts/firewall-lock/src/main.rsFirewallLockArgs::parse
  • Inner lock: contracts/spawn-aware-secp256k1/src/main.rs