Skip to content

Latest commit

 

History

History
655 lines (475 loc) · 36.6 KB

File metadata and controls

655 lines (475 loc) · 36.6 KB

Possibilities

What the structural authorization pattern could enable on CKB.

This document sketches applications — from near-term buildable to long-range speculative — to show the range of what becomes possible when capacity moves by condition, not by key. Each entry includes the problem, the on-chain mechanism with transaction structures and cell layouts, and an honest assessment of what's needed to build it.

The pattern is specified in SPEC-CORE.md. The treasury (shared pool) application is specified in SPEC-TREASURY.md. Everything below is a starting point for builders, not a commitment.


Risk Profiles

Read every entry below against the application risk model in SPEC-CORE §7.6: risk scales with the transaction space that must be exhaustively rejected, not with value or code size. The table classifies each application by which risk multipliers it carries and which trust assumptions survive after the custodian is removed. "Trust-shifted" means the pattern removes the fund custodian but a designated truth-teller (oracle, referee, auditor) remains — a real improvement, but not trustlessness, and it should be named honestly.

Application Tier Risk multipliers Residual trust
Bug bounty Low (with recipient binding — see the front-running caution in its entry) Role-pinned recipient None
Accountability bond Low–Medium Multi-mode script Referee honesty (declared by both parties at creation)
Agent accountability bond Medium–High Multi-mode, bounty arithmetic, evidence liveness, slash front-running Firewall registry governance for blacklist-class violations — trust-shifted, not trustless. None for limit- and type-script-class violations.
Dominant assurance contract Medium Accumulator, multi-mode, per-contributor refund arithmetic None
Protocol dev fund Medium–High (depends on verification option chosen) Multi-phase, pool None (on-chain proof) → auditor threshold → voters, per the verification table
Trustless lending High Price oracle, accumulators, shared pool, liquidation races Oracle provider — trust-shifted, not trustless
Parametric insurance High Event oracle, shared pool Oracle provider — trust-shifted, not trustless
Bridge escrow High (code complexity, not trust) Light-client verifier complexity, consensus-rule parsing Correctness of the verification algorithm only
Quadratic funding High Counting over dynamic sets, ZK verifier, registry state, off-chain computation ZK proof system + registration mechanism

The deployment ladder from SPEC-CORE §7.6 applies: the low-tier applications are not just easier — their audits and test corpora are the reusable evidence base for the tiers above them.


Buildable Now

These use the structural authorization pattern with no major unsolved dependencies. A team with CKB script development experience could build any of these today.


Dominant Assurance Contracts

Problem: Public goods are underfunded because of the free rider problem. "I'd contribute if others would too, but I don't want to be the only one paying." Traditional crowdfunding doesn't solve this — contributors risk wasting effort and attention if the threshold isn't met, and the platform takes a fee either way.

The dominant assurance contract (proposed by Alex Tabarrok, 1998) solves the free rider problem by flipping the incentive: an entrepreneur commits to refunding all contributors PLUS a bonus if the project fails. Contributing has positive expected value regardless of outcome — so the rational choice is always to contribute.

Nobody has deployed this at scale. Crowdfunding platforms won't build something that eliminates their fee. A trustless implementation removes the platform.

Cells:

Assurance pool cell (guarded, open lock):
  type_script: guard_script (authorized_condition = assurance_condition_hash)
  data: version(1) | entrepreneur_lock_hash(20) | target_shannons(8 LE) |
        deadline_since(8 LE) | bonus_shannons(8 LE) | accumulated_shannons(8 LE)

Entrepreneur bonus cell (guarded, open lock):
  type_script: guard_script (authorized_condition = assurance_condition_hash)
  data: version(1) | pool_type_id(32) | bonus_shannons(8 LE)

Contribution receipt cell:
  type_script: assurance_condition_script
  data: version(1) | pool_type_id(32) | contributor_lock_hash(20) | contributed_shannons(8 LE)

Transactions:

Setup (entrepreneur):
  inputs:  [ entrepreneur_wallet ]
  outputs: [ assurance_pool_cell (seed capacity), entrepreneur_bonus_cell (bonus locked) ]

Contribute:
  inputs:  [ pool_cell, contributor_wallet ]
  outputs: [ pool_cell (accumulated += contribution), receipt_cell, contributor_change ]

Success (target reached, anyone triggers):
  inputs:  [ pool_cell, bonus_cell ]
  outputs: [ entrepreneur_payout (pool - target + margin), project_fund (target) ]
  — condition: accumulated >= target

Failure refund (deadline passed, per contributor):
  inputs:  [ pool_cell (since: past deadline), receipt_cell, bonus_cell ]
  outputs: [ pool_cell (accumulated -= contribution),
             contributor_refund (contribution + pro_rata_bonus),
             bonus_cell (reduced) ]
  — condition: accumulated < target AND since past deadline

Condition script logic:

The assurance condition script has three modes:

  1. CONTRIBUTE: Verify receipt cell is correctly formed, pool accumulated field is updated, contributor capacity is transferred.
  2. SUCCESS_CLAIM: Verify accumulated >= target. Permit pool drain to project fund and entrepreneur payout. No receipt required — anyone can trigger.
  3. FAILURE_REFUND: Verify since past deadline AND accumulated < target. Verify receipt cell consumed matches contributor. Calculate pro-rata bonus share: (contributed / accumulated) * bonus_shannons. Verify contributor receives contributed + bonus_share.

What makes this different from a regular crowdfund: The entrepreneur's bonus cell is locked at setup — they can't withdraw it. If the project fails, the bonus automatically distributes to contributors. This makes the entrepreneur's commitment credible and makes contributing a dominant strategy for rational actors.

UTXO contention: Same as crowdfund — contributions are sequential (one per block). For a public goods campaign with moderate interest, this is acceptable. High-volume campaigns need off-chain queuing.


Self-Enforcing Bug Bounties

Problem: Bug bounty programs have a credibility gap. A protocol team promises $X for critical vulnerabilities, but:

  • The payout depends on the team's severity assessment (subjective)
  • The team can dispute, delay, or simply refuse to pay
  • Researchers have been publicly stiffed (see: numerous HackerOne disputes)
  • The bounty amount can be changed or withdrawn at any time

The result is that top researchers under-invest in auditing, because the expected payout is discounted by the probability of not getting paid.

Mechanism: The bounty IS the bug. A guarded cell encodes a protocol invariant in its condition script. If anyone can construct a transaction that satisfies the condition (i.e., violates the invariant), the capacity transfers to them automatically. The exploit is the proof. The proof is the claim. The claim is the payout. No human judgment involved.

Cells:

Bounty cell (guarded, open lock):
  type_script: guard_script (authorized_condition = invariant_condition_hash)
  data: version(1) | invariant_id(4) | bounty_shannons(8 LE) | commit_delay_since(8 LE)
  capacity: the bounty amount

Claim commitment cell (condition cell, phase 1):
  type_script: invariant_condition_script
  data: version(1) | bounty_type_id(32) | commitment(32)
        ← blake2b(violation_evidence ‖ claimant_lock_hash); reveals nothing

Violation proof cell (condition cell, phase 2):
  type_script: invariant_condition_script
  data: version(1) | bounty_type_id(32) | claimant_lock_hash(20) | violation_evidence(variable)

Example — capacity conservation invariant:

A protocol has a token pool that should never decrease below a minimum reserve. The bounty condition script checks:

fn on_consume():
  // Find the protocol's pool cell in cell_deps
  pool_cell = find_cell_dep_by_type(protocol_pool_type_hash)
  
  // Read the pool's current balance
  pool_balance = read_u64_le(pool_cell.data, offset=BALANCE_OFFSET)
  
  // The invariant: pool balance >= minimum reserve
  minimum_reserve = read_u64_le(self.data, offset=RESERVE_OFFSET)
  
  // If the invariant HOLDS, the bounty should NOT be claimable
  // If the invariant is VIOLATED, the bounty pays out
  assert pool_balance < minimum_reserve  // violation detected = bounty earned

  // Recipient binding (SPEC-CORE §5.5): evidence is bound to the claimant
  // by the aged phase-1 commitment, so a mempool copy cannot redirect payout
  commitment_cell = find_input_by_type(commitment_type, since: commit_delay elapsed)
  assert blake2b(violation_evidence || claimant_lock_hash) == commitment_cell.commitment
  assert output_goes_to(claimant_lock_hash)

Front-running caution (recipient binding — SPEC-CORE §5.5): a naive one-transaction claim is a bearer note. The claimant is unknown when the bounty is created (that's the point of an open bounty), so if the claiming transaction simply carries the evidence and names a payout address, the evidence becomes public in the mempool the moment the researcher broadcasts — and anyone can copy it into a competing transaction with the payout redirected. The condition script sees a valid proof either way. The claim must therefore be two-phase commit-reveal: phase 1 publishes only blake2b(evidence ‖ claimant_lock_hash), binding the evidence to the claimant without revealing it; phase 2 reveals the evidence and pays the lock committed in phase 1. The reveal requires the commitment to have aged past commit_delay_since, so a front-runner who sees the reveal cannot race a fresh commitment ahead of it.

Transactions:

Commit claim (phase 1 — evidence stays secret):
  inputs:  [ claimant_wallet (funds commitment cell occupancy) ]
  outputs: [ claim_commitment_cell ]

Claim bounty (phase 2 — invariant violated, commitment aged):
  inputs:  [ bounty_cell, claim_commitment_cell (since: commit_delay elapsed) ]
  outputs: [ claimant_payout (lock = committed claimant_lock_hash) ]
  cell_deps: [ protocol_pool_cell (showing violated state) ]
  witnesses: [ violation_evidence ]
  — condition: blake2b(evidence ‖ claimant_lock_hash) == commitment
               AND payout lock == claimant_lock_hash

Classes of invariants that work:

Invariant type Condition script checks Difficulty
Balance floor Pool capacity < declared minimum Simple
Type confusion Cell with wrong type hash accepted by protocol Simple
Unauthorized spend Protocol cell spent without required authorization Medium
State transition violation Protocol cell transitions to impossible state Medium
Arithmetic overflow Computation produces incorrect result given specific inputs Hard

Limitations: The invariant must be expressible as an on-chain check. Off-chain bugs (frontend vulnerabilities, API key leaks) can't be bounty-encoded. The bounty amount is fixed at lock time — it can't be adjusted without creating a new bounty cell (which means consuming the old one, which means satisfying the condition, which means proving a bug — catch-22 by design).

Why this matters: It's the first credibly-committed bug bounty mechanism. The protocol team can't renege because they don't hold a key to the bounty cell. The researcher knows exactly what they'll earn. The incentive is permanently aligned.


Accountability Bonds

Problem: Two parties want to enforce a commitment without lawyers. A freelancer promises delivery by a date. Two friends make a bet. Co-founders agree on milestones. In all cases, the enforcement mechanism is social — and social enforcement is unreliable, slow, and relationship-damaging.

Mechanism: Each party locks CKB as a bond. A pre-agreed referee (or oracle, or on-chain proof) determines the outcome. The losing party's bond goes to the winner automatically. Neither party can withdraw their bond without the outcome being determined.

Cells:

Bond cell (guarded, open lock):
  type_script: guard_script (authorized_condition = bond_condition_hash)
  data: version(1) | party_a_lock_hash(20) | party_b_lock_hash(20) |
        referee_lock_hash(20) | bond_shannons(8 LE) | deadline_since(8 LE) |
        terms_hash(32)   ← blake2b hash of off-chain agreement text

Referee attestation cell (condition cell):
  type_script: bond_condition_script
  lock_script: referee's lock (referee must sign to create this cell)
  data: version(1) | bond_type_id(32) | winner(1) ← 0x01 = party_a, 0x02 = party_b

Transactions:

Create bond:
  inputs:  [ party_a_wallet, party_b_wallet ]
  outputs: [ bond_cell (capacity = a_bond + b_bond) ]
  witnesses: [ party_a_sig, party_b_sig ]  ← both parties consent

Resolve (referee decides):
  inputs:  [ bond_cell, referee_attestation_cell ]
  outputs: [ winner_payout (bond capacity - fee) ]
  — condition: attestation.winner determines output lock hash

Timeout (no resolution by deadline):
  inputs:  [ bond_cell (since: past deadline) ]
  outputs: [ party_a_refund (a_bond), party_b_refund (b_bond) ]
  — condition: since past deadline, no attestation

Condition script logic:

fn on_consume():
  match mode:
    RESOLVE =>
      attestation = find_input_by_type(attestation_type_hash)
      // Verify attestation was created by the referee (lock script enforces this)
      assert attestation.lock_hash == bond.referee_lock_hash
      winner_lock = if attestation.winner == 0x01: bond.party_a_lock_hash
                    else: bond.party_b_lock_hash
      assert output_lock_hash == winner_lock
      assert output_capacity >= bond_capacity - fee

    TIMEOUT =>
      assert since_elapsed(bond.deadline_since)
      // No attestation present — refund both
      assert output_a.lock_hash == bond.party_a_lock_hash
      assert output_a.capacity >= bond.a_bond
      assert output_b.lock_hash == bond.party_b_lock_hash
      assert output_b.capacity >= bond.b_bond

Variations:

  • Three-outcome: Winner / loser / draw (bond returned to both)
  • Partial resolution: Referee awards a percentage split
  • Multi-referee: N-of-M referees must agree (multi-party approval condition)
  • Oracle-based: Replace referee with an oracle data feed (sports scores, weather data, stock prices)
  • On-chain proof: Replace referee with a verifiable on-chain state check (CI passing, contract deployed, token price threshold)

Agent Accountability Bonds

Problem: Permission systems for autonomous agents define what an agent may do. They give it nothing to lose. A misconfigured or compromised agent operating inside its granted permissions still causes damage, and revocation is always after the fact — someone has to notice, then act, and the harm has already landed. A permission grant with no downside relies entirely on the operator caring.

Bonding inverts the incentive: the operator stakes capacity against their agent's behavior, and anyone who catches a violation is paid to prove it.

Mechanism: The operator locks CKB in a guarded cell bound to an agent identity. Any observer who can demonstrate a violation visible in on-chain structure constructs a slash transaction presenting a violation-proof condition cell. The slasher takes a bounty; the remainder goes to a declared treasury. If no violation is proven, the operator unbonds after a cooldown.

This is ckb-agent-control-hub's flagship use of the pattern, and it composes with ckb-transaction-firewall: the blacklist registry becomes the evidence base for one violation class.

Cells:

Agent bond cell (guarded, open lock):
  type_script: guard_script (authorized_condition = violation_condition_hash)
  data: version(1) | agent_identity_type_id(32) | bond_shannons(8 LE) |
        bounty_bps(2 LE) | treasury_lock_hash(32) | unbond_since(8 LE) |
        firewall_registry_type_id(32)

Violation proof cell (condition cell):
  type_script: violation_condition_script
  lock_script: role-pinned claimant lock   ← see recipient binding, SPEC-CORE
  data: version(1) | bond_type_id(32) | violation_class(1) | evidence(variable)

violation_class:
  0x01 = spend to a Firewall-blacklisted lock hash
  0x02 = capacity exceeding the Permission Cell's maxSpendPerTx
  0x03 = output type script outside allowedTypeScripts

Transactions:

Post bond:
  inputs:  [ operator_wallet ]
  outputs: [ agent_bond_cell ]
  witnesses: [ operator_sig ]

Slash (anyone holding a valid proof):
  inputs:    [ agent_bond_cell, violation_proof_cell ]
  outputs:   [ claimant_bounty, treasury_remainder ]
  cell_deps: [ firewall_registry_cell, agent_permission_cell, offending_cell ]

Unbond (cooldown elapsed, no slash):
  inputs:  [ agent_bond_cell (since: past unbond_since) ]
  outputs: [ operator_refund ]
  witnesses: [ operator_sig ]

Condition script logic:

fn on_consume():
  match mode:
    SLASH =>
      proof = find_input_by_type(violation_condition_hash)
      assert proof.bond_type_id == bond.type_id

      match proof.violation_class:
        BLACKLISTED_SPEND =>
          registry = load_cell_dep(bond.firewall_registry_type_id)
          offending = load_cell_dep(proof.evidence.out_point)
          assert merkle_verify(registry.blkl_root, offending.lock_hash)

        LIMIT_EXCEEDED =>
          permission = load_cell_dep_by_agent(bond.agent_identity_type_id)
          offending = load_cell_dep(proof.evidence.out_point)
          assert offending.capacity > permission.max_spend_per_tx

        TYPE_SCRIPT_VIOLATION =>
          permission = load_cell_dep_by_agent(bond.agent_identity_type_id)
          offending = load_cell_dep(proof.evidence.out_point)
          assert offending.type_hash not_in permission.allowed_type_scripts

      bounty = bond.bond_shannons * bond.bounty_bps / 10000
      assert output_bounty.lock_hash == proof.lock_hash
      assert output_bounty.capacity >= bounty
      assert output_treasury.lock_hash == bond.treasury_lock_hash
      assert output_treasury.capacity >= bond.bond_shannons - bounty - fee

    UNBOND =>
      assert since_elapsed(bond.unbond_since)
      assert output_lock_hash == operator_lock_hash

The evidence liveness constraint. A CKB script cannot query arbitrary historical transactions by hash. It reads inputs, outputs, and cell deps of the transaction it is validating. The logic above therefore requires the offending cell to still be live so it can be supplied as a cell_dep. Once that cell is spent, the evidence is no longer loadable and the violation becomes unprovable by this mechanism.

Two consequences worth stating plainly rather than designing around:

  • Slashing is a race. An agent that immediately consumes its offending output escapes. This bounds the pattern to violations that leave durable state, and makes the bounty a bet on observer speed.
  • Extending to spent evidence requires transaction-inclusion proofs — header deps plus a script that parses block structure and verifies a Merkle path against a committed root. That is a substantial complexity multiplier and moves the application out of the "buildable now" tier.

Front-running. A slash transaction reveals the proof in public before it confirms. Any observer can copy the evidence, substitute their own lock hash, and resubmit. This is the same hazard flagged in the bug bounty entry, and it takes the same mitigation: role-pinned recipient binding, where the proof cell's claimant lock is fixed at proof creation rather than read from the slashing transaction. Identity-pinned binding does not help here, because the claimant is not known when the bond is created.

Cooldown sizing. unbond_since must exceed the realistic detection window for the violation classes in scope. Too short and an operator front-runs discovery by unbonding; too long and honest operators have capital locked indefinitely. This is the same trade-off as the veto window in veiled-ckb's identity anchor, and it has the same shape: the mechanism protects whoever is actually watching.

What bonds cannot cover. Only violations expressed in transaction structure are provable. An agent's config rules — prompt-injection guards, retrieval source restrictions, delegation-depth limits, anything mediated by LLM judgment — live in an encrypted Spore cell that no script can read. Bonds secure the on-chain surface, not the reasoning surface, and describing them otherwise would overclaim.

Variations:

  • Tiered bonds: Bond size scales with the capability set granted, so higher-blast-radius permissions require more at stake.
  • Partial slashing: Forfeit a percentage per violation class rather than the whole bond, letting an agent continue operating after a minor breach.
  • Shared insurance pool: Slashed capacity funds a pool compensating parties harmed by agent misbehavior, rather than a passive treasury.
  • Bond-gated permissions: The Permission Cell's type script requires a live bond cell of sufficient capacity as a cell_dep — no bond, no capability.
  • Watchdog revocation: The same violation proof authorizes revoking the agent's Permission Cell, giving a structural revocation lane alongside the issuer's key-signed one.

Protocol Development Funds

Problem: Open-source protocols need sustained funding. Foundations introduce centralization — a legal entity controls the treasury, a grants committee becomes a gatekeeper, and political dynamics determine who gets funded. The technical problem of "fund good work" becomes the social problem of "who decides what's good."

Mechanism: A treasury pattern pool. Anyone donates. Milestone conditions trigger payouts. The fund has no administrator — only rules about what constitutes a completed milestone.

Cells:

Dev fund cell (treasury pattern — guarded, open lock):
  type_script: guard_script (authorized_condition = milestone_condition_hash)
  data: version(1) | project_hash(32) | total_milestones(4) | completed_milestones(4)

Milestone proof cell (condition cell):
  type_script: milestone_condition_script
  data: version(1) | fund_type_id(32) | milestone_index(4) |
        deliverable_hash(32) | auditor_attestations(variable)

Milestone verification options (from most trustless to most practical):

Verification How it works Trust assumption
On-chain deployment proof Condition script verifies a cell with the expected code hash exists on-chain None — verifiable
ZK proof of computation Condition script verifies a ZK proof that the code passes a test suite Proof system correctness
Multi-auditor attestation N-of-M auditors sign the milestone cell Auditor honesty (threshold)
Single auditor attestation One designated auditor signs Auditor honesty
Community vote Governance-style vote on milestone completion Voter participation and honesty

Transaction (milestone payout):

Milestone payout:
  inputs:  [ dev_fund_cell, milestone_proof_cell ]
  outputs: [ developer_payout (milestone amount), dev_fund_cell (reduced, milestone count incremented) ]
  witnesses: [ auditor signatures or ZK proof ]

Complex but Architecturally Sound

These require additional infrastructure (oracle feeds, off-chain coordination) but the on-chain pattern maps cleanly. A team building these would spend most of their effort on the infrastructure, not on figuring out whether the pattern applies.

Honesty note on oracles (SPEC-CORE §5.6): several of these depend on oracle cells — off-chain facts written on-chain by a designated provider. Per the condition input-class analysis, that makes them trust-shifted, not trustless: the pattern removes the custodian of the funds, but the oracle provider remains a designated truth-teller who can trigger or block payouts by what they attest. That is still a meaningful upgrade (the trusted party can no longer take the funds, only lie about facts — a smaller, more auditable power), but applications in this section should be named and marketed accordingly. The same applies to any condition reading another protocol's mutable on-chain state: an "on-chain price" from a DEX cell is an oracle the adversary can move with capital instead of keys.


Trustless Lending

Problem: Every DeFi lending protocol (Aave, Compound, MakerDAO) has an admin surface: governance tokens that control parameters, guardian keys that can pause, upgrade proxies that can change contract logic. Users trust that governance won't act against them. Sometimes that trust is misplaced.

Mechanism: A lending pool as a treasury. Deposits, borrows, repayments, and liquidations are each a different condition type, all authorized by the same guard script on the pool cell.

Naming note: with a price oracle in the loop this is custodian-less, not trustless — see the honesty note at the top of this section. What the pattern removes is the admin surface (governance keys, pause guardians, upgrade proxies); the oracle provider's honesty remains a live assumption, exactly as it is for Aave or MakerDAO.

Cells:

Lending pool cell (guarded, open lock):
  type_script: guard_script (authorized_condition = lending_condition_hash)
  data: version(1) | total_deposits(8 LE) | total_borrows(8 LE) |
        interest_rate_params(16) | oracle_type_hash(32)

Deposit receipt cell:
  type_script: lending_condition_script (mode: DEPOSIT)
  data: version(1) | pool_type_id(32) | depositor_lock_hash(20) |
        deposited_shannons(8 LE) | deposit_timestamp(8 LE)

Collateral cell (guarded by repayment condition):
  type_script: guard_script (authorized_condition = repayment_condition_hash)
  data: version(1) | loan_id(32) | borrower_lock_hash(20) |
        collateral_shannons(8 LE) | loan_shannons(8 LE) |
        interest_rate(8 LE) | origination_timestamp(8 LE)

Oracle price cell (in cell_deps, created by oracle provider):
  type_script: oracle_type_script
  lock_script: oracle_provider_lock
  data: version(1) | asset_pair(8) | price(8 LE) | timestamp(8 LE) | signature(64)

Transactions:

Deposit:
  inputs:  [ pool_cell, depositor_wallet ]
  outputs: [ pool_cell (total_deposits += amount), deposit_receipt, depositor_change ]

Borrow:
  inputs:  [ pool_cell, borrower_wallet (collateral source) ]
  outputs: [ pool_cell (total_borrows += loan),
             collateral_cell (locked, guarded by repayment condition),
             loan_payout (to borrower) ]
  cell_deps: [ oracle_price_cell ]
  — condition: collateral_value / loan_value >= collateral_ratio (e.g., 150%)

Repay:
  inputs:  [ collateral_cell, borrower_wallet (repayment source) ]
  outputs: [ pool_cell (total_borrows -= loan, capacity += principal + interest),
             collateral_release (to borrower) ]

Liquidate (anyone can trigger):
  inputs:  [ collateral_cell, pool_cell ]
  outputs: [ pool_cell (total_borrows -= loan, replenished with collateral),
             liquidator_bonus (incentive portion of collateral) ]
  cell_deps: [ oracle_price_cell ]
  — condition: collateral_value / loan_value < liquidation_threshold (e.g., 120%)

Key property: Liquidation requires no permission. Anyone who observes an under-collateralized position can construct the liquidation TX and earn the bonus. The condition script verifies the oracle price, checks the ratio, and permits the liquidation. No keeper network. No MEV auction. Just a permissionless incentive.

Depends on: Reliable oracle price cells. Interest rate computation in the condition script (or a pre-agreed rate table). UTXO contention management for the pool cell.


Parametric Insurance

Problem: Traditional insurance requires claims adjusters — humans who evaluate whether an event occurred and whether the claim is valid. This is slow, expensive, and prone to disputes. Parametric insurance removes the adjuster by defining the trigger as an objective threshold (earthquake > 6.0 magnitude, flight > 3 hours late, temperature < -10°C). If the threshold is breached, the payout triggers — no assessment needed.

Mechanism: An insurance pool (treasury pattern). Participants buy policies by contributing premiums and receiving policy receipt cells. When an oracle attestation cell appears confirming the parametric trigger was breached, anyone can trigger the payout.

Cells:

Insurance pool cell (guarded, open lock):
  type_script: guard_script (authorized_condition = insurance_condition_hash)
  data: version(1) | event_type(4) | trigger_threshold(8 LE) |
        oracle_type_hash(32) | policy_count(4) | total_premiums(8 LE) |
        coverage_per_policy(8 LE) | expiry_since(8 LE)

Policy receipt cell:
  type_script: insurance_condition_script
  data: version(1) | pool_type_id(32) | policyholder_lock_hash(20) |
        premium_paid(8 LE) | coverage_amount(8 LE)

Oracle event cell (in cell_deps or inputs):
  type_script: oracle_type_script
  data: version(1) | event_type(4) | measured_value(8 LE) | timestamp(8 LE) | source_id(32)

Transactions:

Buy policy:
  inputs:  [ pool_cell, policyholder_wallet ]
  outputs: [ pool_cell (premiums += premium, policy_count += 1),
             policy_receipt, policyholder_change ]

Claim (event triggered, anyone can submit per policyholder):
  inputs:  [ pool_cell, policy_receipt ]
  outputs: [ pool_cell (reduced by coverage), policyholder_payout (coverage_amount) ]
  cell_deps: [ oracle_event_cell ]
  — condition: oracle.measured_value breaches trigger_threshold
               AND oracle.timestamp within policy period

Expire (no event, pool operator reclaims residual):
  inputs:  [ pool_cell (since: past expiry) ]
  outputs: [ operator_reclaim ]
  — condition: since past expiry, no claims outstanding

Depends on: Oracle infrastructure that can attest to real-world events (weather APIs, flight data, seismic data). The oracle cell's lock script ensures only the designated oracle provider can create it.


Bridge Escrow Without Bridge Operators

Problem: Cross-chain bridges are the biggest single point of failure in crypto infrastructure. The root cause is always the same: a set of key holders (validators, guardians, multisig members) whose compromise or collusion drains the bridge. Wormhole ($320M), Ronin ($625M), Nomad ($190M) — all exploited human key holders.

Mechanism: The CKB-side bridge escrow is a guarded cell. The condition cell contains a cryptographic proof that a deposit occurred on the source chain. The condition script IS a light client verifier — it checks the proof against the source chain's consensus rules. No validators. No guardian set. No keys.

Cells:

Bridge escrow cell (guarded, open lock):
  type_script: guard_script (authorized_condition = bridge_proof_condition_hash)
  data: version(1) | source_chain_id(4) | source_chain_genesis_hash(32) |
        total_locked(8 LE)

Bridge proof cell (condition cell):
  type_script: bridge_proof_condition_script
  data: version(1) | escrow_type_id(32) | recipient_lock_hash(20) |
        amount_shannons(8 LE) | source_tx_hash(32) |
        block_header(variable) | merkle_proof(variable)

Condition script logic (sketch):

fn on_consume():
  // 1. Verify the block header is valid
  //    - Check proof-of-work (Bitcoin) or validator signatures (PoS chain)
  //    - Verify header chain links to a known checkpoint
  header = parse_block_header(self.data)
  assert valid_consensus_proof(header, source_chain_id)

  // 2. Verify the deposit TX is included in the block
  merkle_proof = parse_merkle_proof(self.data)
  assert verify_merkle_inclusion(source_tx_hash, header.tx_root, merkle_proof)

  // 3. Verify the deposit TX sends the claimed amount to the bridge address
  //    (this may require parsing the source chain's TX format)
  assert deposit_matches(source_tx_hash, amount, bridge_deposit_address)

  // 4. Release funds to recipient
  assert output_lock_hash == recipient_lock_hash
  assert output_capacity >= amount_shannons

Why it's speculative: Building a light client verifier as a CKB script is significant engineering. For Bitcoin, you need to verify proof-of-work and parse Bitcoin transaction format inside CKB-VM. For Ethereum, you need to verify validator signatures and Merkle-Patricia proofs. These are implementable (CKB-VM is Turing-complete with generous cycle limits) but represent months of specialized work.

Why it's worth thinking about: If someone builds it, the security model of CKB bridges changes fundamentally. Instead of "trust these N validators," it becomes "trust this verification algorithm" — which can be audited, formally verified, and is immutable once deployed.


Quadratic Funding Without a Platform

Problem: Gitcoin has demonstrated that quadratic funding works for public goods. But Gitcoin is a company. It administers the matching pool, runs the rounds, sets the rules, takes a cut, and has been pressured to exclude projects. The matching formula is supposed to be neutral — but the platform running it is not.

Mechanism: A matching pool (treasury pattern). Individual donations create contribution receipt cells. When the round closes (time-gated by since), anyone can trigger distribution. The condition script implements the QF formula: each project's match is proportional to the square of the sum of the square roots of its individual contributions.

The math (for the condition script):

For project P with individual contributions c₁, c₂, ..., cₙ:

match(P) = (Σ √cᵢ)² - Σ cᵢ

Total matching distributed proportionally:

payout(P) = matching_pool × match(P) / Σ match(all projects)

Cells:

QF matching pool (guarded, open lock):
  type_script: guard_script (authorized_condition = qf_condition_hash)
  data: version(1) | round_id(4) | round_end_since(8 LE) |
        matching_pool_shannons(8 LE) | project_count(4) |
        project_registry_hash(32)  ← merkle root of registered projects

QF contribution receipt:
  type_script: qf_condition_script
  data: version(1) | pool_type_id(32) | project_id(4) |
        contributor_lock_hash(20) | contributed_shannons(8 LE)

QF distribution proof (condition cell for settlement):
  type_script: qf_condition_script
  data: version(1) | pool_type_id(32) | distribution_merkle_root(32) |
        zk_proof(variable)  ← proof that distribution follows QF formula

Why ZK is likely needed: Computing the QF formula for many projects and many contributors inside a CKB script is computationally expensive. The practical approach: compute the distribution off-chain, generate a ZK proof that the computation is correct, and verify the proof on-chain. The condition script only verifies the proof — not the full computation.

Depends on: ZK proof verification in CKB scripts. Off-chain computation infrastructure. Project registration mechanism.


The Common Thread

Every application above follows the same structure:

  1. Capacity is held by rules, not by people. The guarded cell has an open lock. The type script is the sole gatekeeper. No key can override the rules.

  2. Conditions are verified by scripts, not by committees. Whether it's a hash preimage, an oracle attestation, a ZK proof, or a multi-party approval — the condition script checks it mechanically.

  3. Anyone can trigger a valid action. No permission, no relayer, no keeper with special access. If you can construct a valid transaction, you can trigger the action. This creates natural incentives for participation (liquidation bonuses, bounty payouts, relay fees).

  4. Once deployed, nobody can change the rules. Immutability is the feature. The cost is that bugs are permanent. The benefit is that nobody can rug you, censor you, or change the terms after you've committed.

The guard script stays the same across all of them. What changes is the condition script. Each new condition script expands the range of what can be structurally authorized. The pattern grows at the edges — in the condition scripts that the community builds.

graph TB
    G[Guard Script<br/>one reusable binary] --- T[Treasury<br/>condition]
    G --- B[Bug Bounty<br/>condition]
    G --- A[Assurance Contract<br/>condition]
    G --- E[Escrow / Bond<br/>condition]
    G --- L[Lending<br/>condition]
    G --- I[Insurance<br/>condition]
    G --- BR[Bridge Proof<br/>condition]
    G --- Q[QF Distribution<br/>condition]

    style G fill:#1a1a2e,color:#fff
Loading