What Lives On-Chain
The anchor contract holds the small amount of persistent state that remains once Skyhook’s finality machinery has done its work. It stores three things: the hashes of finalized Zcash block headers, the Merkle Mountain Range peaks that summarize them, and the inclusion roots against which claims are checked. Full 1,484-byte headers are never stored, since a 32-byte hash is enough wherever the design needs to name a block. Only rollup finalization can write to the anchor, and the protocol has no administrative key.
Transaction anchors and note anchors
The anchor keeps two kinds of commitment that answer different questions, and confusing them is the most common mistake newcomers make.
- A transaction anchor commits to complete transactions by transaction ID. It supports the statement that a payment occurred: a claim uses it to prove that its transaction is included in a finalized block. It says nothing about whether a note is valid.
- A note anchor commits to individual notes by note commitment. It supports the statement that a spendable note exists: a claim uses it to prove that the note being spent is genuine. It says nothing about transaction inclusion.
The implementation tracks the two separately, and dedicated tests pin the distinction, because errors caused by mixing them up don’t explain themselves.
Claims and other reads
A claim arrives with a Merkle path from its transaction to a finalized root. The contract folds the path, compares the result with the anchor, and pays out on a match or reverts on a mismatch. No other authority takes part in the decision.
Other operations read the same state: a refund checks that no claim finalized first, and a cancellation checks that no acceptance binds the request. Because every exit described in The Life of a Swap reads one source, the system is consistent by construction rather than by coordination.
Writes and upgrades
Corrupting the anchor would compromise every path that depends on it at once. Writes therefore happen only when a rollup is finalized, whether shared or one-shot. No administrative key can alter the anchor and no upgrade path bypasses finalization.
The anchor’s format changes only through the same path. A migration is finalized under the old rules before it takes effect under the new ones, so an upgrade can’t strand settled history.
Two kinds of finality
Rollups can be fully sampled or root-anchored, and the anchor keeps the two apart. Each finalized rollup is recorded with its mode, and the anchor tracks the last fully sampled block separately from the last finalized block of any kind. Fully sampled rollups draw their tail samples from the history since the last fully sampled block, never from a block whose finality rests on someone’s agreed root, so the default guarantee can’t be weakened by a root another party accepted.
Deployment parameters
Skyhook’s contracts are a public good that anyone can deploy. Each deployment sets its own parameters, chiefly the difficulty floor and the leftover address that receives funds a script leaves behind, and chooses how they are updated: a DAO, a multisig, or any other mechanism its operators prefer. A stale or badly set floor can at worst invite spam; it can’t move funds or halt the bridge, and participants can agree to ignore it.
Storage
A header hash takes 32 bytes against a 1,484-byte header body, a saving of more than 46 to 1. The number of peaks grows only logarithmically with the number of leaves, and each finalized rollup adds one root. Total anchor state therefore grows with the number of finalized rollups rather than with the length of the chain, and the contract’s storage stays bounded.