Statechains, Mercury Layer, and Spark each let you transfer the practical ability to spend a Bitcoin UTXO without writing the transfer to the chain. They differ in privacy, in who co-signs, and in how badly they fail when something breaks. None are trustless. All depend on old signing material being deleted at the right moment.
The primitive. A two-of-two between you and an entity. To transfer, the entity rotates its key share so only the new owner can co-sign. Old owners hold older backup transactions that mature later than yours; you race them on chain if it ever comes to that.
A statechain implementation where the co-signing server is blind. It signs partial signatures without learning the UTXO, the public key, or the final on-chain signature. Strong privacy. Heavy validation burden on the receiver. Public repo archived in March.
A productized version with threshold operators (FROST), a tree of leaves so balances split, SSPs that route Lightning, and a token layer for stablecoins. Beta mainnet, two operators at launch. Documented incidents in the months since.
The shape of the trick is older than its name. You and a server share a Bitcoin output that neither of you can spend alone. You hand a sealed envelope to a friend; the envelope holds the right to ask the server to co-sign with them instead of with you. Your friend does the same thing later, to someone else. The coin never moves on chain — only the right to ask the server moves, off-chain, in private.
The catch is what happens when somebody cheats. The server can refuse to play; the previous owner can collude with the server; and on Bitcoin, without an Eltoo-style update mechanism, the workaround is a chain of pre-signed backup transactions whose lock-times decrease with each transfer. Whoever holds the freshest backup wins on chain — provided they're awake when the older ones mature.
Below is a working version of a statechain. You hold the parcel as Alice. Click transfer to send it to Bob, then to Carol, then to Dave. The current block advances; each new backup gets a slightly earlier lock-time. The bars show how much margin each owner has before their backup matures — and how much the safety window shrinks with every hop.
When you've moved it a few times, hit sleep · old owner attacks. That simulates the current owner's wallet going offline while a previous owner broadcasts an old backup. Watch the log. The race is the whole point.
c = 144 blocks per transfer (≈ 1 day). Initial window h₀ = 2,016 blocks (≈ 14 days). Bitcoin block height advances by 144 per simulated day.The hard part of a statechain isn't producing signatures. It's making sure the previous signing material is gone. If the entity keeps an old share, a former owner can come back later and ask it to co-sign a transaction spending the coin from the past. There is no cryptographic proof that a key was deleted. Mitigations exist — trusted hardware, distributed operators, public commitment trees, watchtowers, decrementing lock-times — but every one of them is an assumption.
The server cannot steal alone. But it can collude with someone who used to own the coin. That is not the same thing as trustlessness. — the gist of every statechain critique
The decrementing lock-time fix gives the current owner a small window in which their backup matures before all earlier ones. The window is c blocks, set by the protocol. In practice, with c = 144, the current owner has about a day. If they go offline for longer, an older backup can win.
Mercury Layer takes the statechain pattern and makes the server blind. The server still co-signs every transfer, but it never learns the UTXO it's touching, the aggregate public key, the final signature that lands on chain, or the contents of the backup transaction. It signs partial blinded signatures; it counts how many it's signed; it knows nothing else.
That privacy comes with a trade. Because the server can't read the transaction, it can't spot a malformed one. Validation falls entirely on the client. The September 2024 disclosure by Conduition found five separate ways an honest receiver could be defrauded by a malicious sender, all of them validation gaps. The lesson was unambiguous: don't validate serialized backup transactions. Reconstruct them from a strict template, then check the signatures match the reconstruction.
Blind co-signing sounds like marketing. It isn't. It's a 1982 cryptographic primitive — David Chaum's blind signature — that does precisely what the name says: a signer produces a valid signature on a message they cannot read.
The intuition. Imagine you need a notary to stamp a document but you don't want them to read it. You put the document in a sealed envelope with carbon paper between the cover sheet and the page inside. The notary stamps the envelope; the carbon transfers the stamp through to the document; the document is stamped; the notary never read a word.
Schnorr blind signing is the cryptographic version of that. The user wraps the real signing request in a secret blinding factor, sends the wrapped thing to the signer, the signer signs it without ever seeing the original, the user removes the blinding. What lands on chain is a perfectly normal Schnorr signature on the original transaction — and the signer cannot recognise it as something they helped produce.
A UTXO is an unspent Bitcoin output — a coin sitting on chain, waiting to be spent. To spend it, someone has to produce a valid signature for a transaction message m. That message isn't text; it's the cryptographic digest of "spend this specific UTXO, to these outputs, with these amounts and conditions." If a server sees m, it can usually figure out which coin is being spent. That's where the privacy problem starts.
In a Mercury-style setup, the coin is locked to an aggregate public key:
The corresponding "full" private key would be p = o + s, but that key never exists anywhere — it's permanently split. The user knows o, the server knows s, neither alone can sign. That's the entire reason this kind of arrangement is called non-custodial.
A Schnorr signature has three ingredients.
The public key. If the private key is the scalar p, the public key is the elliptic curve point P = p · G, where G is the standard generator on secp256k1. Multiplying a scalar by G is a one-way operation — you can compute P from p easily, but recovering p from P is the discrete log problem. Hard.
A nonce. The signer picks a fresh single-use secret k and shares its public form R = k · G. The nonce must be unique per signature — reusing it leaks the private key. Forever.
A challenge. The challenge ties the signature to its context:
The challenge essentially says: "this signature is for this nonce, this public key, this exact transaction." The signature scalar is then:
And a verifier confirms it by checking σ · G == R + e · P. That equation is why Schnorr works. Substitute: σ · G = (k + e·p) · G = k·G + e·p·G = R + e·P ✓.
Each party brings its own piece. They each contribute half of the nonce:
Each party then computes a partial signature using its own private share and the same shared challenge e:
It works because Schnorr is linear — partial signatures simply add. Substituting:
Which is exactly a normal Schnorr signature under the aggregate key P and aggregate nonce R. Verifies the same way; on chain it's indistinguishable from a single-signer Taproot signature.
If the user gives the server everything it needs to compute the real challenge — R, P, m — the server learns four things, all of which are bad for privacy.
Which UTXO is being signed. The transaction message m identifies the input being spent (directly, or via the sighash construction). The server can say, "this user is signing a spend of this particular coin."
The aggregate public key P. That's the on-chain key the coin is locked to. Knowing it links the signing session to a specific statecoin, deposit, or address.
The transaction itself. Where it's going, what amount, what fee, whether it's a withdrawal or a transfer or a sweep.
The final on-chain signature. Once the user combines the partials and broadcasts, the resulting (R, σ) appears in a Bitcoin block. The server saw R and P already, so it can scan the chain and recognise "that's the transaction I helped sign." The server becomes a watcher of its own users.
Now suppose the user does not send R, P, or m at all. Instead, it computes the real challenge e = H(R ‖ P ‖ m) locally and wraps the signing request with fresh blinding randomness:
From the server's view, the request is just random-looking signing material. It can't recover e, and it can't recover R, P, or m because it never received them in the clear.
The challenge e is a fingerprint of the signing context. It binds together R, P, and m — see all three and you can rederive e. See e alone and you can't reverse the hash to recover the inputs (that's what cryptographic hashes are for), but seeing e alongside the on-chain transaction would let you confirm the match. Blinding hides that fingerprint behind randomness:
The server cannot recompute a match from a candidate Bitcoin transaction it sees later, because the on-chain signature uses the unblinded signing context and the server only saw the blinded request.
The server treats the blinded request as the thing to sign:
It used its private share s; it produced a valid blinded response. But it doesn't know what real challenge e that response corresponds to. Its honest log entry reads, "I issued one blinded partial signature for session X." That log entry is the only thing the server can publish.
The user receives σ_s', removes the blinding to recover the partial signature on the real challenge, and combines it with its own partial:
What lands on chain is a perfectly normal Schnorr signature on the real m, validating against the real P and the real R. From the chain's perspective, nothing about it looks "blinded" — that's the point.
A tempting simplification is to write e' = e + α and imagine the user just subtracts α at the end. That would not work. Watch:
To recover σ_s by subtraction, you'd need to subtract α · s — and the user doesn't know s. So a literal "challenge offset and subtract" doesn't work. Real blind Schnorr protocols arrange the algebra so the user can unblind using only its own random values plus public information; this typically involves blinding the nonce as well as the challenge, and exploiting the fact that the verification equation σ · G = R + e · P can be massaged into a form the user can produce. Read the figure as conceptually saying "the user wraps, the server signs the wrapped thing, the user unwraps." Trust that the algebra exists; it's been published since the early 2000s.
Compared to the unblinded case, what the server learns shrinks dramatically.
m.P — it stays inside the user's hash.m — never on the wire.The session counter is what makes the protocol auditable. When a receiver accepts a transferred statecoin, they verify the server's signature count matches the number of legitimate transfers in the statecoin's history. More signatures than transfers means the server signed something it shouldn't have — which is what collusion looks like from the outside.
In a statechain, the server is in the loop on every transfer. Without blinding, that turns the server into a structured surveillance database — who transferred what to whom and when, with the on-chain fingerprints to prove it. Blinding lets the server still do its job (co-signing, rotating shares, enforcing the protocol) without that surveillance power. The protocol still works; the privacy holds.
The simplest mental model: a normal signature request is like handing the server a document and asking them to co-sign. The server reads the document. A blind signature request is putting the document inside a cryptographic envelope and asking the server to sign the envelope. The server contributes a valid signature without ever opening the envelope. The user later peels the envelope off — and is left with a valid signature on the real document.
Schnorr blind signing has a known weakness. If a signer runs many concurrent blind signing sessions, an attacker can sometimes combine several blinded responses to forge a signature on a message the signer never authorised. This is the ROS attack — Random inhomogeneities in an Overdetermined Solvable system, Wagner 2002, formalised against Schnorr by Benhamouda et al. in 2020. It's not theoretical; it's a real concern for anyone building blind-Schnorr in production.
Mercury defends two ways. First, the SGX enclave caps the number of concurrent signing sessions to a small number, so the ROS attack's required pool of blinded signatures isn't reachable. Second, the server publishes a signature counter per session — every partial it has issued is counted. The receiver, when accepting a transferred statecoin, checks that the server's counter matches the number of legitimate transfers in the statecoin's history. More signatures than transfers means the server signed something extra, which is what collusion looks like.
That counter is the only auditable thing the server publishes. The whole privacy guarantee — and the whole trust model — hinges on it being honest.
The user holds a secret share o. The server holds a secret share s. The aggregate public key is P = O + S. To transfer ownership, the new owner generates o₂; the server updates its share to s₂ = s₁ + o₁ − o₂; the aggregate stays the same: O₂ + S₂ = O₁ + S₁ = P. The on-chain Taproot output never changes. What changes is who can cooperate with the server to spend it.
The server is supposed to delete s₁. Whether it actually does is the entire trust assumption.
The summary above hides the orchestration. Below is a step-by-step walkthrough of exactly what each party computes, what they send to whom, and what they end up holding. The numbers below are real — fresh 256-bit scalars sampled from secp256k1's order, with t = (o₁ − o₂) mod n and s₂ = (s₁ + t) mod n computed for actual.
Click next step to advance. The active lane lights up. The fresh value at each step appears in orange. The deletion at the end is shown as a strikethrough — that's the moment the protocol either holds or fails.
P = O + S.P.h₀.Order matters: if the deposit confirmed first, a refusing server could trap the funds with no exit.
o₂ and sends transfer info to Alice.h₀ − (n−1)·c.s₂ = s₁ + o₁ − o₂ and deletes s₁.Spark generalizes the pattern. Instead of one server it has a threshold of operators, signing FROST-style; instead of a fixed-denomination UTXO it has a tree of leaves; instead of asking users to manage Lightning channels it asks SSPs to do it for them; and on top of all of that it carries a token layer for stablecoins.
The trust model goes from "trust this one server forever" to "trust at least one of the relevant operators to delete its old key share at the moment of transfer." Better. Not equivalent to trustless. The realistic threat is correlated failure — a shared signer bug, a shared custody arrangement, a shared legal demand — not independent dishonesty.
Statechains transfer a UTXO whole; a 0.5 BTC statecoin is a 0.5 BTC payment, no more, no less. Spark splits a deposit into a tree of leaves, so a wallet can pay any amount by selecting leaves that sum to it (and possibly splitting one). The trade is that small leaves can't be exited unilaterally — anything below 16,348 sats costs more in fees than it carries in value.
Below is a wallet with eight leaves and a request from Bob for 173,000 sats. Pick leaves until you cover it. The summary tells you whether you went over, what change a split would produce, and whether any selected leaf is below the unilateral exit floor.
Spark wallets run a coin-selection algorithm to pick leaves that sum to the target. If no exact match exists, an operator splits a leaf in two — one for the recipient, one for change. Below 16,348 sats, a leaf can be transferred but not unilaterally withdrawn.
Pick leaves to start.
Mercury's backup transaction and Spark's branch / leaf / refund transactions are the same kind of safety object: a valid Bitcoin transaction signed now, but held off-chain and broadcast only if the cooperative path fails. Pre-signing does not move coins. It creates an already-authorized escape path.
The difference is shape. Mercury pre-signs one backup spend for a whole statecoin. Spark pre-signs a transaction tree: branch transactions split the deposit, leaf transactions isolate spendable units, and refund transactions pay the current owner after timelocks. Transfers normally update who owns the leaves and replace the per-leaf refund state; the root deposit remains where it is.
Alice is paying Bob 173,000 sats for a repair invoice. Her wallet chooses leaves, Spark operators rotate each selected leaf to Bob, and any excess becomes Alice's change. Bitcoin L1 sees no transaction.
A single 800,000-sat Alice deposit, fanned out into eight 100,000-sat leaves at deposit time. Over the next 23 days, three of the four users (Bob, Carol, Dave) get involved. Two of those transfers need partial amounts that don't match any subset of existing leaves — so the SDK falls back to a leaves swap with the SSP (the actual mechanism in services/leaf-manager.ts: selectLeaves first, then selectLeavesWithSwap). After a swap, the wallet holds leaves from the SSP's deposit tree, not Alice's. Carol coop-exits one of those swap leaves; Dave is forced into a unilateral exit through the SSP's pre-signed chain. Every box is clickable.
wallet.transfer({ receiverSparkAddress, amountSats }).Fee schedule: Spark→Spark BTC currently free. Spark→Lightning 0.25% + routing. Lightning→Spark free for receiver, 0.15% for sender.
Constraints (beta): only leaves above 16,348 sats exit unilaterally; single-session process; wallet locked during exit; exact broadcast ordering required; fee UTXOs must be staged.
Spark looks simple from the SDK side — initialize a wallet, send to a Spark address, done. Underneath is a lattice of moving parts: a threshold of operators running a custom FROST signing protocol, a tree of pre-signed Bitcoin transactions extending from each on-chain deposit, Spark Service Providers that hold Lightning nodes on users' behalf, and (optionally) issuers running a token layer on top of all of it. Below is each part, in detail.
If terms like "aggregate key," "threshold signature," or "pre-signed transaction" don't already feel obvious, the rest of this section will land sideways. The five blocks below are the mental models the rest depends on. Once they're in place, everything that follows is just naming parts.
Imagine a small safe holding some bitcoin. The safe has a lock. To take the bitcoin out, you have to produce the right "key" — which in Bitcoin means a digital signature, a number only the holder of a secret value (a private key) can produce. That's a Bitcoin UTXO. Most Bitcoin lives in safes like this.
What this actually is — a Bitcoin output locked to a public key. Spending requires a signature that validates against that key. Whoever holds the matching private key can spend the output; nobody else can.
Now imagine a safe with TWO locks instead of one. You hold the key to the first lock. A server holds the key to the second. Neither key alone opens the safe — both must turn at the same time. To produce the spending signature, you and the server must cooperate. Each of you signs a partial signature; the partials add together into one valid signature on the safe's address.
This is the basic shape of all three protocols on this site (statechains, Mercury, Spark). The user holds one lock; the server holds the other.
What this actually is — a Schnorr-aggregated public key Y = U + S, where U is the user's public point and S is the server's. Spending requires a co-signed Schnorr signature with each side contributing using its private share.
Take the two-lock safe. Now replace the server's lock with a special arrangement: instead of one server, there are five people. Each holds a fragment of the second lock. Any THREE of them can combine their fragments to act as the server. Two alone can't. One alone definitely can't.
This is what Spark adds on top of Mercury's design. Mercury has one server (single lock). Spark distributes the second lock across multiple operators with a threshold rule. To "be the server" you need at least t of n operators cooperating. The benefit: you no longer trust a single vendor. The catch: you have to trust that at least one (or threshold-many) of those operators will honestly delete their fragment when the time comes.
What this actually is — a t-of-n threshold Schnorr signature using FROST. The operator share s is split into Shamir secret shares; any threshold subset of operators can collectively produce a valid partial signature on behalf of S. A single operator alone cannot. Distributed Key Generation (DKG) is how the shares are created without ever assembling the full s in one place.
Imagine writing a check today, signing it, but writing on it "do not cash before May 21." Banks won't process it until May 21. Bitcoin works the same way — you can attach a timelock to a transaction so the network refuses to confirm it until the lock matures.
Now imagine signing a whole stack of these — all signed today, by all the parties who need to sign, but each one with a later "do not cash before" date than the last. The stack is your fallback plan. If the cooperative path stops working, you can broadcast each one in turn, waiting through each timelock.
This stack is what Spark calls "the tree." When you deposit, you and the operators jointly pre-sign a chain of transactions, all today. They live in your wallet. If operators ever stop cooperating, you can broadcast them in order to extract your money on chain — slowly, but unilaterally.
What this actually is — a chain of pre-signed Bitcoin transactions with relative-time locks (CSV — CheckSequenceVerify). Spark's "tree of leaves" is exactly this: a deposit, a branch transaction (CSV ~1024 blocks), a sub-branch (CSV ~512), a leaf (CSV ~256), a refund (CSV ~144). Each is signed at deposit time and held off-chain until needed.
Here's the trick that makes "transferring ownership without moving the coin" possible. The safe has an address (call it Y) printed on the outside. The address is fixed — it can't change without an on-chain transaction. But the locks inside can be quietly rearranged: the bank can swap its lock to a new one in such a way that the new owner's key, paired with the new bank-lock, still opens safe Y.
The arithmetic is a one-line trick. If old user is U₁ and old bank is S₁ with U₁ + S₁ = Y, the new state is U₂ + S₂ = Y where S₂ = S₁ + (U₁ − U₂). Same total, different decomposition. The bank's lock is rotated by exactly the difference between the old and new user keys. The address on chain doesn't change. Who can open the safe does.
The trust assumption: the bank has to actually destroy its old lock. If it keeps both old and new locks lying around, the previous user can still open the safe with the old combination. This is the unsolvable problem all three protocols carry — nothing on chain proves the old lock was destroyed. You have to trust the implementation (HSM, SGX enclave, threshold of operators) to do it.
What this actually is — additive share rotation. The aggregate Y = U + S is invariant across transfers because S is updated by the transition scalar t = u_old − u_new. The old share must be deleted; otherwise the previous owner plus the server (or threshold of operators) can co-sign on behalf of the now-stale state.
You may have heard "Merkle tree" used in Bitcoin contexts. The trees in Spark's deposit are not Merkle trees. They share the word "tree" because of branching, but they're different objects entirely.
A Merkle tree is a hash tree. Each leaf is a piece of data; each non-leaf is the hash of its children; the root is a single fingerprint that commits to the whole set. Given the root and a small "Merkle proof" (one hash per level), you can prove a specific leaf belongs to the set without revealing the others. Merkle trees show up in Bitcoin block headers (the block commits to all its transactions via a Merkle root) and in SPV proofs.
Spark's transaction tree has nothing to do with hashing. Each non-leaf is a real Bitcoin transaction that spends its parent and creates outputs the children can spend. If you broadcast the parent, the child becomes spendable; if you broadcast the child, its child becomes spendable. The branching exists because one deposit can fund many spendable units — not because anyone wants a single hash to commit to everything.
One sentence each:
What this actually is — a distinction between a cryptographic commitment scheme (Merkle / hash tree) and a UTXO consumption hierarchy (transaction tree). If you ever encounter a Merkle tree in a statechain context, it is almost certainly a separate proof-of-publication structure (e.g. the Mainstay system in old CommerceBlock Mercury) used for audit, never for the transfer mechanism itself.
With those six blocks in place, the rest of this section is just naming parts. The "four actors" below are who holds which lock or runs which service. The "tree of leaves" is the stack of post-dated checks (block 4) — not a Merkle tree (block 6). The "threshold key" is the second lock split among operators (block 3). The Lightning section is the courier that pays invoices for you. Tokens are dust UTXOs tagged with extra data. Unilateral exit is broadcasting the post-dated checks in order. And every transfer is a lock-swap (block 5). Now back to Spark.
Spark documentation conflates these in places. They are distinct roles with distinct trust assumptions.
holds the user share of every aggregate key
u per leafjointly hold the operator share of every aggregate key
S via Shamir secret sharingroutes Lightning, absorbs 0-conf risk, takes a fee
creates and controls a BTKN-issued asset
Before a deposit can be received, the operators run a Distributed Key Generation ceremony. The output is an aggregate operator public key S whose corresponding private key s exists nowhere — it's threshold-shared across operators using Shamir secret sharing. Any t-of-n operators can collectively sign on behalf of S; fewer than t can't.
When a user deposits, the wallet generates its own user secret u, computes U = u·G, and the deposit address is the Taproot output corresponding to Y = U + S. To spend, the user contributes a partial signature using u, and a threshold of operators contributes the operator side using their Shamir shares of s. The result is a single Schnorr signature on Y — indistinguishable on chain from any other Taproot spend.
Spark's docs emphasize "customized" FROST. The customization buys three properties standard FROST doesn't quite give:
s₂ = s₁ + t, just distributed across operators.A Spark deposit isn't just a UTXO. It's the root of a tree of pre-signed Bitcoin transactions, signed at deposit time and held off-chain. Each transaction in the tree is a normal Bitcoin transaction that could be broadcast unilaterally; in practice, almost none ever are.
The tree typically has three levels: root → branch → leaf. Each level has its own timelock that the next layer down has to beat. The structure encodes the unilateral exit path: to claim a specific leaf without operator help, you broadcast the chain of pre-signed transactions from the root down to that leaf, waiting through each timelock in turn.
| Depth | Transaction | What it does | Relative timelock |
|---|---|---|---|
| L1 root | deposit_tx | The Taproot output users actually send BTC to. Locked to Y = U + S. |
— on chain — |
| Branch | branch_tx | Spends the deposit; outputs are sub-aggregate keys for each branch. Pre-signed at deposit time by user + operators. | CSV 1024 |
| Sub-branch | subbranch_tx | Splits a branch into smaller leaf groups. Pre-signed. | CSV 512 |
| Leaf | leaf_tx | The final spendable unit. Output value = leaf size in sats. Spendable by current owner via the operator-cooperated key, or unilaterally after the chain matures. | CSV 256 |
| Refund | refund_tx | Per-leaf "exit" transaction. Pays the current owner's L1 address. Pre-signed at every transfer (with a fresh timelock that decrements per transfer, like a statechain). | CSV 144 |
Two consequences of this structure worth flagging.
Multiplicity is a knob with two ends. A wallet can ask for "more leaves, smaller each" — useful for fast small payments, since a transfer doesn't have to split. The trade is that more leaves means a deeper tree and more pre-signed transactions per deposit, which inflates the data the wallet must keep, and pushes some leaves below the 16,348-sat exit floor where unilateral withdrawal stops being economic.
Refund timelocks decrement on transfer. Just like Mercury's backup transactions, each new owner of a leaf gets a fresh refund transaction with a slightly earlier locktime than the previous owner's. The newest owner's refund matures first, so if any older owner tries to broadcast their stale refund, the current owner has a window to publish theirs and win the race on chain.
The user's Spark wallet doesn't run a Lightning node. There are no channels, no liquidity to manage, no rebalancing. When a user wants to pay a Lightning invoice, an SSP does it on their behalf — and the atomicity comes from a HODL-invoice construction that ties the Spark leaf transfer to the Lightning payment's preimage.
Receiving Lightning payments works in reverse. The user generates an invoice, the SSP holds the channel and receives the payment; once the SSP has the preimage, the operators rotate fresh leaves to the user. The receiver never had a Lightning node, never had channels, never paid for inbound liquidity.
Fees as published: Spark→Lightning 0.25% of the amount plus the LN routing fee paid by the SSP; Lightning→Spark free for the receiver, 0.15% from the sender via route hint pricing. Spark→Spark in BTC is currently free. The fee structure is expected to change.
BTKN is Spark's token standard. It's a successor to LRC20 (a Bitcoin tokenization scheme that embedded data in script outputs). Where BTKN differs is that token data lives in two places: the Bitcoin address itself (via a small tweak that's invisible to non-token-aware wallets), and in metadata that Spark Operators validate.
Y = U + SWhat this means in practice: a stablecoin holder is exposed to three trust layers stacked on top of each other.
The Issuer SDK exposes mint, burn, and freeze as first-class operations. Freeze is not a bug; it's a feature that compliance-focused issuers want. Holders should know they hold it.
The cooperative exit is uneventful: user and operators jointly sign a normal transaction sending funds to the user's chosen L1 address. Fee per the formula 250 × sat/vB + 750. Done in seconds.
The unilateral exit is the test case. It's beta. Reading the docs carefully, the actual procedure is roughly this:
The whole sequence is "single-session" — the wallet has to complete it without losing state. There's no resume; if the wallet gets reinstalled mid-exit and the broadcast plan is lost, the user is in trouble. And throughout the exit window, the wallet is locked — no transfers, no payments. For a 4-level tree at 1024/512/256/144 CSV blocks, that's ~13 days of locked wallet plus L1 confirmation time per layer.
This is why "unilateral exit" is real but operationally heavy. The cooperative path exists for a reason.
Spark publishes a status page. The incidents on it are the closest thing to a public reliability dataset. A selection from the past year:
What this dataset actually shows. Liveness incidents are common but bounded. No theft, no permanent loss, no integrity compromise reported in any of the above. The pattern is operational degradation that the user experiences as "the app doesn't work right now," sometimes for a few hours. The launch SSP is a single point of failure. When Lightspark's SSP went down for nearly four hours, Lightning stopped working for everyone. A second SSP would help. Leaves can get stuck. The Dec 2025 incident is the most worrying because it's not just liveness — leaves in a renewal state can't be transferred or exited until the operators resolve the underlying state inconsistency.
Beta means this category of incident is expected. The question is how the rate trends as the protocol matures.
Alice has Spark wallet installed. She has run the deposit flow once: she generated a user share u_A, the operators jointly generated their share of S, and the deposit address corresponds to Y_A = U_A + S. Alice sent 100,000 sats to that address, the deposit confirmed on Bitcoin, and the operators co-signed a tree of pre-signed transactions: branch_tx, sub-branch_tx, leaf_tx (one per leaf), and a refund_tx for each leaf paying back to Alice's L1 address with a CSV-locked timeline.
Alice's wallet now shows: 100,000 sats in 4 leaves of 25,000 each (multiplicity setting). She holds u_A, the four leaf-specific user shares, the full pre-signed exit chain for each leaf, and the operators' attestations.
Bob's wallet generates an identity key. Bob's "Spark address" is a public identifier derived from that identity key — it's not a Bitcoin address; nothing about it appears on chain. Bob shares it with Alice over any channel.
wallet.transfer({ receiverSparkAddress: bob, amountSats: 50000 })Alice's wallet runs coin selection: it picks two leaves of 25,000 sats each (sum = 50,000 — exact match, no split needed). For each selected leaf, it does the rotation dance with the operators.
For each leaf being transferred, Bob's wallet generates a fresh user share u_B and a public point U_B = u_B · G. Alice's wallet encrypts her old user share u_A for this leaf to Bob's identity key. Bob receives u_A, computes the transition scalar t = u_A − u_B, and sends t to the operators (blinded? no — Spark doesn't blind operator-side signing the way Mercury does; operators see metadata).
Each of t participating operators updates their Shamir share of s by adding t. The Shamir reconstruction of the new s' would be s' = s + t, so S' = S + t·G. The new aggregate is:
The leaf's on-chain key didn't change. What changed is the user share that pairs with the operators' rotated share. Each participating operator deletes its old share contribution. The signature counter for that leaf increments.
Bob's wallet and the operators jointly produce a fresh refund_tx for this leaf — same structure as Alice's, but paying to Bob's L1 address (which Bob's wallet derives from his identity key) and with a slightly earlier CSV value than Alice's old refund_tx. Decrementing locktime, statechain-style: Bob's refund matures one window before Alice's.
Bob's wallet validates the new refund_tx against the leaf's history — it checks that the leaf is unspent on chain, that the operator counter matches the number of legitimate transfers, and that the refund's locktime decrements correctly. If anything fails, Bob's wallet rejects the leaf.
The leaf is now Bob's. From Alice's view: balance −50,000. From Bob's view: balance +50,000. From Bitcoin's view: nothing happened. From the operators' view: two leaves rotated, two counters incremented, two old shares destroyed.
No L1 transaction, no fees beyond what Spark charges (currently 0 for Spark→Spark BTC). Total elapsed time: typically under a second per leaf, depending on operator latency.
The aggregate keys for the two transferred leaves did not change — the same Bitcoin Taproot outputs are still the on-chain anchor. What changed is:
u_A → Bob's u_B).The trust assumption is the same one statechains have always had: at the moment of transfer, enough operators must have honestly deleted their old share contributions. Spark's improvement over a single-server Mercury isn't that the assumption goes away — it's that breaking it requires multiple operators to fail simultaneously, plus a previous owner cooperating. Correlated failure (shared signer software bug, common custody arrangement) is the realistic threat model.
Bob calls wallet.cooperativeWithdraw({ destinationAddress, leafIds }). The operators receive the request, co-sign a normal Bitcoin transaction spending the leaves' Taproot outputs to Bob's L1 address, the wallet broadcasts. The cooperative exit fee follows 250 × sat/vB + 750 per leaf. The operators delete their shares for the spent leaves. Done in one Bitcoin block.
Bob's wallet has the full pre-signed exit chain for each leaf. For each:
For a 4-level tree the total wall-clock exit time is days, the wallet is locked throughout, and any leaf below 16,348 sats can't be exited at all because the L1 fees per level exceed the leaf's value. This is why the cooperative path is the default — and why a misbehaving operator set is genuinely costly to escape from.
A Spark wallet, in one breath: the user holds key shares and pre-signed exit chains for every leaf they own; operators hold the threshold counterpart and run the FROST signing protocol; SSPs hold Lightning channels on the user's behalf; issuers (if any) control the policy of issued tokens. Transfers are off-chain key rotations on tree-of-leaves UTXOs anchored to Bitcoin. Exits are either cooperative (fast) or a multi-day broadcast of pre-signed transactions through CSV-locked levels. None of it is trustless. All of it is deployable on Bitcoin today.
To make all of the above concrete: a single Spark cycle with real numbers — every block height, every locktime, every scalar relationship. Alice opens a wallet, deposits 100,000 sats, pays Bob, Bob receives a Lightning payment, and eventually exits to L1. (Alternative ending: what unilateral exit would have cost.) Numbers are illustrative — block heights match the rest of the site at 947,435 baseline; CSV values match Figure 9.
Alice installs the wallet. It generates an identity key and a fresh user secret u_A. Operators run distributed key generation; the resulting operator share S exists nowhere as one secret — only as Shamir shares across operators. Alice gets a deposit address corresponding to Y_A = U_A + S. She sends 100,000 sats to that address. The block confirms.
In parallel with the on-chain confirmation, the wallet and operators jointly pre-sign a four-leaf tree. Every transaction in the tree is signed at this moment; none will be broadcast unless cooperative recovery fails.
invariant: U_A + S = Y_A, and the deposit UTXO matches Y_A on chain.
Bob installs a wallet, generates an identity key, sends Alice his Spark address (a public derivation of his identity key — not a Bitcoin address; nothing about it appears on chain). Alice's wallet calls wallet.transfer({ receiver: bob, amountSats: 25000 }). Coin selection picks leaf 1 — exact match, no split needed.
The per-leaf rotation runs:
invariant: U_B + S' = U_B + (S + t·G) = U_B + S + (U_A_1 − U_B) = U_A_1 + S = Y_1. The leaf's on-chain key is unchanged.
From Alice's view: balance −25,000. From Bob's view: balance +25,000. From Bitcoin's view: nothing happened. From the operators' view: leaf 1 rotated, sig counter incremented, old share destroyed.
A friend pays Bob a Lightning invoice. Bob doesn't run a Lightning node — the SSP holds the channel. The invoice was generated against the SSP's node, with a route hint pointing at Bob's Spark identity. The payment lands at the SSP; the SSP gets the preimage; Bob's wallet learns the preimage; operators rotate fresh leaves to Bob to match the amount minus fees.
The 50,000-sat leaf is structurally identical to a normal Spark leaf — it has its own pre-signed exit chain back to L1, its own refund_tx paying Bob's L1 address, its own CSV-locked timelocks. The only thing "Lightning" about it is its provenance.
Bob calls wallet.cooperativeWithdraw({ destination: bc1q…, leafIds: [leaf_1_alice, leaf_5_lightning] }). The operators respond, co-sign a single Bitcoin transaction spending both leaves' Taproot outputs to Bob's L1 address. Wallet broadcasts.
Done. Bob is back on L1 with 71,750 sats in his chosen address. The pre-signed exit chains for these leaves are now historical artifacts — the on-chain UTXOs they referenced are spent.
Suppose the operators stop responding. Bob has to broadcast the pre-signed chain himself, level by level, waiting through each CSV timer. For one leaf (the 25,000-sat one):
For the 50,000-sat leaf: same procedure, possibly sharing branch_tx if it's already been broadcast. Both leaves exit eventually but the wallet is unusable for ~10 days. And if either leaf had been below 16,348 sats, the per-level fees would have exceeded the leaf value — at which point unilateral exit isn't economic, and the user is genuinely stuck unless cooperative recovery resumes.
cost of an uncooperative operator set: ~10 days, ~1,200 sats overhead, and a wallet you can't use.
That's a single-leaf exit. A wallet with many leaves repeats the leaf and refund stages per leaf (or batches them where the protocol allows). The key insight from the alternative ending: cooperative exit is so much faster and cheaper that operators have enormous practical leverage over users — even when the unilateral path technically exists.
Ark answers a different question than the statechains before it. Mercury and Spark ask "how do two people pass one on-chain coin back and forth without touching the chain?" Ark asks "how do a thousand strangers share one on-chain coin at the same time, each able to leave alone?" The answer is a VTXO — a virtual UTXO — and the entire protocol is the machinery that keeps a VTXO spendable off chain while never taking away its owner's right to walk it back onto Bitcoin without anyone's permission.
It becomes legible once you separate two clocks. On the fast clock, users hand VTXOs around off chain at the speed of an operator signature. On the Bitcoin clock, those VTXOs are periodically anchored, renewed, or exited through real on-chain transactions. Almost every confusion about Ark comes from collapsing those two clocks into one.
The operator co-signs a virtual transaction. The receiver can spend the new VTXO immediately, before any Bitcoin transaction confirms.
A round commits a fresh tree of VTXOs to Bitcoin in one transaction. The receiver gets a new exit path; the old VTXO is forfeited atomically.
Here is the trick the marketing words ("Virtual Mempool", "batch swap") hide. The operator does not create one on-chain UTXO per user. It creates one on-chain output and hangs a whole tree of pre-signed transactions off it. The root is the single output that lands on Bitcoin. Intermediate transactions split it into branches. The leaves are the individual VTXOs. Thousands of independent ownership claims share one Bitcoin transaction output — and because of Taproot and MuSig, that output looks on chain like an ordinary single-signature payment.
To get your money out without the operator, you don't get to spend the shared output directly. You broadcast your branch of the tree, transaction by transaction, from the root down to your leaf. That is the whole design in one sentence: shared on chain, individual off chain, and a pre-signed ladder connecting the two.
| Level | Transaction | What it does | Timelock |
|---|---|---|---|
| Root | commitment_tx | The one transaction that actually lands on Bitcoin. Its single output funds the entire tree and is locked to an n-of-n key over everyone in the round. Ark Labs calls this the commitment transaction; Second calls it the round transaction. | — on chain — |
| Branch | branch_tx | Pre-signed, off chain. Splits the output into sub-groups (Second fans out four ways per node). Carries an absolute timelock so the operator can reclaim the whole subtree once the round expires. | CLTV (absolute) |
| Leaf | leaf_tx | The individual VTXO. A Taproot output with two paths: the cooperative key path (owner + operator), and the unilateral exit path the owner can take alone after a relative delay. | CSV (relative) |
There is a hole in the plan above, and it is the most important thing about Ark. For your unilateral exit to be safe, the branch and leaf transactions must be fixed — the operator must not be able to rewrite the tree after the fact and strand your coin. The clean way to enforce that would be a covenant: a Bitcoin opcode (Jeremy Rubin's OP_CHECKTEMPLATEVERIFY) that says "this output may only be spent by this exact pre-committed transaction." Bitcoin does not have that opcode today. So covenantless Ark — the only kind running on mainnet — fakes it.
The operator is going to publish one on-chain output and tell a thousand users "your money is in there." For that claim to be self-custodial, each user needs a transaction they can broadcast — without the operator — that peels their slice out of the shared output and onto an address only they control. The danger is that the operator later builds a different tree, or refuses to honour the one it promised. We need the tree of branch and leaf transactions to be frozen the moment the round is created.
A covenant is a spending rule that constrains where an output's money can go next, enforced by the network. With OP_CHECKTEMPLATEVERIFY, the operator could lock the root output to a hash of the exact branch transaction, that branch to a hash of the exact leaves, and so on. Nobody could deviate, because every full node would reject a non-matching spend. No coordination, no online requirement — the chain is the referee. Bitcoin has no such opcode in consensus today, so this version of Ark stays on paper.
If Script won't enforce the rule, the participants enforce it themselves. Every internal output of the tree — root, every branch — is locked to an n-of-n aggregate key over all the parties whose money flows through it, plus the operator. Using MuSig2, those n keys aggregate into one Taproot key, and the spend looks like a single signature on chain:
An n-of-n lock means no subset can move the money — not the operator alone, not a clique of users. The only spends that can ever happen are the ones everybody already signed.
At round creation, before any money is committed, every participant signs every transaction in the tree with a freshly generated, single-use key — and then deletes that key:
This is the covenant. The set of valid spends was fixed at signing time, and once the keys are gone, not even the original signers can produce a different signature. A pre-signed transaction nobody can re-sign is, for all practical purposes, an enforced template.
Could the parties collude to rewrite the tree? Only if they could reconstitute the n-of-n key, which requires every ephemeral key. So the guarantee is delightfully cheap: the tree is immutable as long as at least one participant actually deleted their key. You don't have to trust the operator, and you don't have to trust the other users — you only have to trust that you, yourself, deleted yours. Then the worst the rest of them can do is exactly what you already agreed to.
A real covenant needs nobody online. This fake covenant needs everybody online at the same time, because an n-of-n signature can't be completed without all n parties. That is why Ark works in rounds: the operator gathers everyone who wants to settle right now, they all co-sign one tree together, and the root goes on chain. If you were offline, you simply weren't in that round — you wait for the next one. This single constraint explains the entire rhythm of Ark.
One more piece. The operator funds the root output with its own bitcoin and would like that capital back if a round goes stale. So every internal transaction also carries an absolute timelock (CLTV): after the round's expiry height, the operator may sweep the whole subtree. Before that height, the operator can't touch it — only the cooperative path or a user's own exit can move funds. The leaves carry a relative timelock (CSV) instead: once you broadcast your exit branch, you must wait out a cooling-off window before the coin is finally yours, which gives the operator a chance to object if you're trying to exit a VTXO you already forfeited (more on that below).
Covenantless Ark, in one breath: lock every node of the tree to an all-of-us key, sign every transaction once, delete the keys so nobody can ever sign anything else, and lean on timelocks so the operator can reclaim what nobody claimed. No new opcode, no trusted custodian — just a promise made permanent by destroying the ability to break it.
Because the tree needs everyone's live signature (§6), settlement happens in rounds. The operator runs them on a cadence — Second targets one every 1–2 hours; Ark Labs frames the same act as a batch swap that produces a new commitment transaction. Whatever the name, the shape is identical: gather the participants, build and co-sign one tree, put its root on chain, and hand everyone a fresh VTXO with a reset expiry.
Each wallet comes online and tells the operator which VTXOs it wants to refresh (or which fresh funds it wants to board). In Arkade this is a signed RegisterIntent PSBT.
The operator lays out the VTXO tree. Every participant MuSig2-signs their branch and exit transactions — the n-of-n pre-signing from §4 — and deletes their ephemeral key.
The operator broadcasts the single on-chain transaction — the round / commitment transaction. Once it confirms, every VTXO in the tree has Bitcoin-level finality.
Each user signs a forfeit handing their old VTXO to the operator, tied to a connector so it only takes effect if step 3 landed. The new VTXO is now live.
When you refresh, your old VTXO does not vanish — you still physically hold its pre-signed exit ladder, and that ladder is still valid on Bitcoin. So Ark makes you sign a forfeit transaction: a transaction that hands the old VTXO to the operator. The operator keeps it as insurance. If you ever try to exit a VTXO you already refreshed away, the operator broadcasts your forfeit and claws the coin back — you burn your own fees and gain nothing.
But a forfeit creates its own danger: what if you sign the forfeit and the operator pockets your old coin without ever putting your new one on chain? That is what connectors prevent. The forfeit transaction is built to require a connector output as a second input — and that connector only comes into existence when the new round transaction confirms. So the forfeit is unspendable until your new VTXO is real. Either both happen or neither does.
Here is the cost that explains why VTXOs expire at all. When the operator broadcasts a round, the root output is funded with the operator's own bitcoin. Your old VTXOs are forfeited to it in exchange — but the operator can't actually spend those forfeited coins until their round's timelock expires. So at any moment the operator has real capital locked up, fronting the new round while waiting weeks to recover the old one.
That float isn't free, and you pay for it. Refresh fees include a liquidity charge that scales with how much runway you're asking the operator to cover:
Refreshing a coin that still has weeks of life costs more than one about to expire, because you're asking the operator to carry more time. This is also why expiry exists in the first place: it is the clock on which the operator gets its capital back. Ark is, underneath, a liquidity-provision business wearing a payments protocol.
Rounds are slow (hours) and need everyone online, which would make Ark useless for actual payments. So between rounds, Alice can pay Bob now: she and the operator co-sign a new spend VTXO that chains directly off Alice's existing leaf. Bob can spend it instantly. Second brands this arkoor — literally ark out-of-round; Ark Labs routes it through the Virtual Mempool, where independent VTXO spends form a DAG and execute in parallel.
Alice signs a virtual transaction spending her VTXO, creating a new spend VTXO for Bob plus her change.
The operator co-signs and promises not to co-sign a conflicting spend of Alice's input. No round, no on-chain transaction.
Usable instantly. But until he refreshes it into a round, Bob is trusting that Alice and the operator don't collude to double-spend.
No L1 transaction has happened. The chain only learns of it later, if Bob refreshes, offboards, or exits.
Use it immediately. For small amounts, Bob can treat a spend VTXO like pocket cash. He can even pass it onward — but each hop lengthens the chain and widens the set of past parties he's implicitly trusting not to collude.
Refresh it. For larger amounts, Bob joins the next round. That converts the payment into a refresh VTXO with a clean unilateral exit, a reset expiry, and zero dependence on Alice behaving later. Change he receives from his own refresh is trustless from the start — he can't collude against himself.
Offboard or exit. To get real L1 bitcoin, Bob cooperatively offboards with the operator (cheap, atomic). If the operator is gone or hostile, he broadcasts his pre-signed exit ladder himself. That is the emergency path, not the everyday one.
Boarding is the one VTXO whose exit is just two transactions deep — it hasn't been folded into a deep tree yet.
No liquidity, no on-chain footprint, near-instant. This is the fast clock.
Refreshing is how a spend VTXO becomes trustless again — and how you beat the expiry clock.
Use this whenever the operator is cooperative. The emergency exit exists for when it isn't.
Unilateral and unstoppable — no one can prevent it. But it costs one on-chain transaction per level, so deep trees and small VTXOs make it expensive, even uneconomic when fees spike.
One quietly elegant property: an emergency exit broadcasts shared branch transactions. If Alice exits first, she puts the upper branches on chain — and Bob, Carol, and Dave, who sit under the same branches, now have less of the tree left to broadcast. Early exiters subsidise later ones. A bank-run on an Ark operator gets cheaper per user as it proceeds.
Everything above — the VTXO tree (Fig. 12), covenantless pre-signing (Fig. 13), the round with its forfeit + connector (Figs. 14–15), arkoor (Fig. 16) and the liquidity clock — wired into one sandbox. Each moment is shown two ways, side by side: an ownership tree (who holds what, and the exit ladder) and a full transaction graph (every transaction — boardings, the round tx, the pre-signed tree txs, the connectors, forfeits, arkoor and exits — with each output linked to the input that spends it). Take the guided tour for the canonical story, or free-play: board users, run a round to mint the tree, pay out-of-round, refresh to settle, or walk a coin back to L1 with a unilateral exit. Watch the on-chain footprint stay tiny while four people transact.
amount × expiry_delta ÷ 365 × rate), and one round mints one block here. The mechanics are faithful — one on-chain root per round, n-of-n pre-signing with key deletion, connector-gated forfeits, the arkoor trust window, a shared absolute expiry, and CSV exits.Ark is a protocol shape, not a product. Two teams ship it with different surfaces and different bets. Both run covenantless, both use the round + forfeit + connector machinery above — they diverge on what they optimise the rest of the stack for.
Ark Labs frames Arkade as "a programmable execution layer for Bitcoin" — an operating system for money, where VTXO transactions run in a Virtual Mempool and settle to Bitcoin through batch swaps.
Second ships bark, an open-source Ark wallet, behind a "painless API" for adding Ark, Lightning, and on-chain payments to an app. The protocol is described through plain wallet operations.
| Dimension | Ark Labs · Arkade | Second · bark |
|---|---|---|
| Public name | Arkade, by Ark Labs | bark, by Second |
| Settlement term | Batch swap → commitment transaction | Round → round transaction |
| Fast path | Virtual Mempool preconfirmation (DAG) | Arkoor out-of-round payments |
| Round cadence | Continuous batch swaps | ~1–2 hours (configurable) |
| VTXO lifetime | Per-operator policy; renew before batch expiry | ~30 days, server-configurable |
| Operator trust | TEE-isolated Arkade Signer + remote attestation | Hash-locked forfeits; trustless exits on board/refresh |
| Best fit | Programmable off-chain Bitcoin applications | Wallets & payment apps wanting Ark + Lightning + L1 |
Ark is not a rollup and not a sidechain. There is no separate consensus system proving every virtual transaction to Bitcoin. The fast path is operator-coordinated preconfirmation; the safety net is simply that you already hold Bitcoin-valid transactions that unroll your claim back to L1.
That net is real but not free. Exit depth grows with tree depth and with chained off-chain spends, so a small VTXO can become uneconomic to exit when fees spike. The interactivity requirement (§6) means you can only settle in a round you were online for. And expiry turns liveness into a hard requirement: if your wallet doesn't refresh in time, the operator's right to recycle that liquidity becomes part of your security story. Ark therefore shifts the central UX question from "can I exit?" to "will my wallet keep my VTXOs fresh and exit-ready without me thinking about it?"
Sources: Arkade overview, Arkade VTXOs, Arkade Virtual Mempool, Arkade Signer / security, Second intro, Second VTXO types, Second rounds, Second forfeits & connectors, Second liquidity, Second exit, covenantless Ark (clArk), connectors, Bitcoin Optech: Ark.
In 2018 Ruben Somsen sketched the first statechain. A 2-of-2 between a user and an entity holds a Bitcoin UTXO. The user has a transitory key — a private key whose corresponding public point sits inside the 2-of-2. To transfer ownership, the current owner simply gives the transitory key to the new owner. The entity promises to only ever co-sign with the holder of the latest transitory key, and that promise is enforced cryptographically: every transfer carries an adaptor signature binding the entity's secret. If the entity ever co-signs with two different owners on the same UTXO, anyone watching can subtract the two adaptor signatures and recover the entity's private key. Cheating is punished by losing all funds the entity controls.
That is the original. It is elegant, and it makes three assumptions that turn out to be load-bearing:
Mercury Layer and Spark are each a renegotiation of some subset of those assumptions. Each fixes one or two and inherits the rest. The grid below reads dimension-by-dimension; the tag on each cell says how that design choice relates to the original.
transitory key that the current owner hands forward to the next.
o; the server rotates its s so the aggregate P is unchanged. (Figure 4.)
↻ changed
c = 144 blocks. The newest owner races any older backup on chain.
↻ workaround
t of them must cooperate to sign or rotate.
↻ changed
The most important thing the original had — and the most important thing both derivatives gave up — is the adaptor-signature accountability. In Somsen's design, cheating is cryptographically punished: equivocate, your key leaks, your funds become anyone's. There is no "trust the operator to delete its share." There is "if the operator misbehaves, it loses everything."
Mercury and Spark replaced that mechanism with operational ones — a published signature counter, an SGX enclave attestation, a threshold of operators, watchtowers, decrementing locktimes. Each is plausible. None is a cryptographic guarantee. They are deployable on Bitcoin today, which the original strictly speaking is not (without eltoo, the original's "latest state wins" loses its teeth too).
Mercury improved privacy and lost cryptographic accountability. Spark improved topology and granularity, lost privacy, and lost cryptographic accountability. Neither solved the deletion problem; both made it more deployable.
That's the whole picture in two sentences. Each derivative is the original minus a cryptographic guarantee, plus a different operational property. There is no free lunch — only different lunches.
| Dimension | Statechains | Mercury Layer | Spark | Ark |
|---|---|---|---|---|
| On-chain object | Locked UTXO, 2-of-2 | Taproot shared-key UTXO | Tree of leaves under L1 root | Batch output with VTXO tree |
| Transfer granularity | Whole UTXO | Whole UTXO | Partial — leaves split & merge | UTXO-like VTXOs |
| Server / operator | Single co-signer | Single blind co-signer | Threshold operators + SSPs | Ark operator / Arkade signer |
| Custody | Cannot spend alone | Cannot spend alone | Cannot spend without user | Pre-signed exits preserve user claim |
| Trust at transfer | No collusion with old owner | Server / HSM deletes old share | ≥ 1 (or threshold) operators delete | Operator does not double-sign preconfirmed VTXOs |
| Privacy from server | Design-dependent | Strong — blinded co-signing | Operators see metadata | Implementation-dependent |
| Exit path | Cooperative · pre-signed backup | Cooperative · timelocked backup | Cooperative · branch & leaf chain | Cooperative offboard · branch & leaf exit |
| Works on today's Bitcoin | Some variants | Yes | Yes | Yes |
| Lightning | Complementary | Lightning Latch (HODL invoice) | Built-in via SSP | Interop via swaps / Bark rails |
| Tokens | None | Not primary | BTKN + Issuer SDK | Arkade assets |
| Main weakness | Whole-UTXO, key deletion | Single server, validation burden, archived | Beta, small operator set, exit complexity | Operator preconfirm trust, expiry, exit cost |
Read across each row, not down the columns. A statechain isn't a worse Spark — it's the primitive both others descend from. Each makes the same trade in a different place.
Three real failures, scrubbed forward in time. Pick a scenario; drag the playhead across the timeline; watch the events fire and the loss accumulate.
No theft yet.
Concrete losses behave the same in every system: the entire UTXO or leaf, minus the attacker's fee. The numbers below come from documented protocol limits, observed Spark incidents, and the September 2024 Mercury disclosure.
| Failure | System | Direct theft? | Temporary lock? | What to watch |
|---|---|---|---|---|
| Old owner + entity collusion | All | Yes | — | Full UTXO / leaf value |
| Mercury sequence 0xFFFFFFFF bug | Mercury | Yes | — | Full statecoin value |
| Missed dispute window | All | Yes | — | Window (often hours, sometimes minutes) |
| Timelock exhaustion | Statechains, Mercury | Possibly | Yes | Remaining blocks before backup matures |
| Server / operator liveness failure | All | — | Yes | Backup delay · exit complexity |
| Spark leaves below 16,348 sats | Spark | — | Yes | Leaf size, not total balance |
| High L1 exit fees | All | — | — | sat/vB × number of exits |
| Whole-UTXO mismatch | Statechains, Mercury | — | — | UTXO denomination vs payment |
| Token freeze / depeg | Spark tokens | Possibly | Possibly | Issuer policy / reserves |
The sharpest failures are the ones where the user believes they own a coin off-chain, but an older state can still win on chain. The loss is simple: the entire UTXO or leaf, minus whatever fee the attacker paid.