Component

Joining

A join fills empty slots in the tree: one new leaf, or a whole cohort that the operator builds off-chain and grafts in as one subtree for the price of one transaction. The covenant checks only that the slots were empty and that the new money is paid in, so each joiner checks their own leaf before they pay.

A single join

The transition for one leaf is JOIN_0. Its witness proves that a slot holds the empty node, carries the new leaf's hash and amount, and carries the operator's signature. The script folds the empty node up the path and requires the result to match the root the tree output commits to, which shows the slot was empty. It then folds the new leaf up the same path and requires the transaction to recreate the tree output under the new root, holding the old total plus the new leaf's amount. The extra money must come from another input; the covenant does not care whose.

A cohort graft

A cohort is a group of members grafted together into one aligned subtree: a block of 2h consecutive slots under one node at height h. The transition is JOIN_h. The operator builds the cohort's subtree off-chain and the witness carries only its top node, a 32-byte hash and an 8-byte sum. The script checks that the slot held the empty node of height h, folds the new node up the D − h levels above it, and requires the tree output to grow by the subtree's sum.

Because the script walks only the levels above the slot, a bigger cohort is a smaller transaction. At depth 16:

Graft cost at depth 16 (from design/graft.md)
TransitionMembersTransaction, vBPer member, operator fundsPer member, members fund
JOIN_01937937about 995
JOIN_24872218about 280
JOIN_66474311.6about 70
JOIN_82566792.7about 61
JOIN_101,0246140.60about 59
One output in an on-chain batch43

Each height is its own script, and the set of scripts is fixed when the tree is created. The reference set carries JOIN_0 and JOIN_2; a deployment that wants 256-member cohorts compiles JOIN_8 in at creation. A slot of height h takes any cohort of up to 2h members, with the unused slots left empty. Placing a cohort in one subtree also sets up the cheap removals later: the sweep and the cohort rewrite both work on an aligned subtree.

What the covenant does not check

The script sees the grafted node's hash and sum, and nothing below them. It cannot tell a real subtree of 256 leaves from 32 random bytes. That is what keeps the graft one constant-size transaction, and it has a precise consequence. If the operator grafts a node with no real tree behind it, nobody can ever prove a leaf under it, so the value it brought stays in the tree output for good. No value is created, because the sums still balance, and nothing else in the tree is affected: every other leaf stays payable. The Lean theorem join_sound states it: a join fills a slot that was empty, the output grows by the grafted sum, and every other position keeps its contents.

Who pays

The covenant requires the new sum to be paid in, and leaves open who pays it. There are three ways to fund a cohort.

The operator funds the graft.
The operator supplies the whole sum from its own input. Members hold no on-chain coins; each buys their balance off-chain, over Lightning, after the graft confirms, or through a hash-locked voucher that the covenant enforces (see swaps). The operator carries the risk that a member never pays. This is the cheap case: under 1 vB per member for a cohort of a thousand.
Each member funds their own leaf.
Each member adds an input to the graft transaction and signs it, about 58 vB each. The transaction cannot be broadcast until every member has signed, so one absent member stalls the cohort until the operator rebuilds it without them. An unsigned graft leaves every member's coins where they were.
Mixed.
The operator funds some leaves and members fund others. This changes nothing for anyone, because each member's safety rests on their own path.

What a joiner checks before paying

A member who signs an input to the graft checks the unsigned transaction first (spec 9.2):

  1. Input 0 spends the current tree output, with the expected amount.
  2. The empty slot folds up its path to that output's root.
  3. Their own leaf folds up their path inside the subtree to the grafted node, with every sum recomputed.
  4. Output 0 commits to the root that the grafted node folds to, with the old amount plus the subtree's sum.
  5. Their leaf's fields are as agreed: amount, their own keys, the evictor and the lease.
  6. Their own inputs and change are as agreed.

They then sign with a signature that covers every output, so their input can only be spent into a transaction whose tree output contains their leaf. They do not need to check anyone else's leaf: by the conservation property, a co-member's bad leaf cannot make a good one unpayable.

A member who pays off-chain has no input to sign. They wait for the graft to confirm, check the same path against the confirmed root, and only then pay. Paying first means trusting the operator to graft.

Deeper