An explainer · for everyone · no prior knowledge assumed
The plumbing of CLPR
How a message gets from one blockchain to another with no bridge to trust. The Cross Ledger Protocol, explained from nothing.
Act I · The problem
Why two ledgers cannot just talk
Know what a ledger is, why two of them cannot see each other, and why the usual fix makes every message only as safe as the party in the middle.
Section 1of 16
A ledger is a shared record
Before cross-ledger anything, one idea has to be solid: what a ledger is. Not the finance kind, the blockchain kind, and the two words are close enough to cause trouble.
A ledger, here, is a shared record that many computers keep identical copies of. Nobody owns it. When someone wants to add a line, every computer gets the proposal, they compare notes, and the line is only written once enough of them agree. The rules for “enough” differ from network to network, but the result is always the same: one more line that every copy has and that nobody can quietly change afterwards.
Five copies of one ledger
Wider than a phone; scroll it sideways if you need to.
Two consequences matter for everything that follows. First, a sealed line is a fact about the whole network, not about one computer. Second, a network can vouch for a line: its validators can put a joint signature on a short summary of the whole ledger, and anyone who knows the network’s public signing identity can check that signature. A state proof is that signed summary plus the path from the summary down to one particular line. Hold that thought.
Wider than a phone; scroll it sideways if you need to.
Check yourself: Why can't a single computer change a line that has already been sealed?
Because every other copy still has the original, and the network only trusts what enough copies agree on. One dissenting copy is simply overruled, as the simulation shows when you tick the box.
Section 2of 16
Ledgers cannot see each other
Now take two of these networks. Each is a world of its own. Nothing written in one ledger is visible from inside the other. A program running on Ledger A cannot look up a balance on Ledger B, cannot call a program there, cannot even tell whether Ledger B exists.
Wider than a phone; scroll it sideways if you need to.
That blindness follows from how ledgers work. In general, a ledger only writes a line if every validator can check it on its own. “Go and look at the other network” fails that test: hundreds of machines cannot all look and be sure they saw the same thing at the same moment. So the two islands stay islands.
Wider than a phone; scroll it sideways if you need to.
But people keep wanting to build things that span them: lock a token on one ledger and issue a matching one on another, let a program on a private network ask a public one to do something, settle a trade whose two legs live on different chains. Every one of those needs a message to cross the water in a way the receiving ledger can rely on.
Section 3of 16
Why a trusted party in the middle is the weak point
The obvious solution is to appoint someone to do the looking. Call them a relayer, an oracle, a committee, a bridge. They watch Ledger A, and when something relevant happens they tell Ledger B, signing the report with a key that Ledger B has been told to trust.
That works, in the sense that messages arrive. The problem is what Ledger B is actually trusting. It is not trusting Ledger A. It is trusting whoever holds that key. If the key is stolen, or the committee members collude, or the program that produces the signature has a bug, Ledger B will accept a message that Ledger A never sent, and it has no way to notice.
Wider than a phone; scroll it sideways if you need to.
Who has to be honest for a message to be safe?
Wider than a phone; scroll it sideways if you need to.
Adding more keys raises the price of the attack. It does not change its shape: there is still a party in the middle whose failure Ledger B cannot detect, and every message is exactly as safe as that party. CLPR sets out to remove the party altogether.
Check yourself: In the committee design, what exactly does Ledger B check when a message arrives?
Only that three of the five committee keys signed it. It never sees anything from Ledger A. Whether the committee told the truth is not something Ledger B can find out.
Act II · The idea
Proof instead of trust
Replace the party in the middle with a proof the receiving ledger checks itself, see what that leaves out, and meet everyone a message passes through.
Section 4of 16
What CLPR does instead: proof, not trust
CLPR (“Clipper”, for Cross Ledger PRotocol) starts from the trick in section 1. Ledger A’s validators already sign summaries of their ledger as part of sealing lines. So instead of asking a middleman “what happened on A?”, Ledger B is handed a state proof: typically the validators’ signature on a summary, plus the path from that summary down to the exact line that says “Ann’s program sent this message”. Ledger B checks that the signature really is Ledger A’s, using the signing identity it keeps on file for A. Then it follows the path down to the line. Only when both hold, and its own checks on numbering and hashes pass, does it believe the message.
Wider than a phone; scroll it sideways if you need to.
The party carrying the proof is still there; CLPR calls it an endpoint: a program that moves messages and their proofs between ledgers. But look at what it can and cannot do. It can deliver, delay, or refuse. It cannot forge a message, because none of its own keys can make Ledger B accept one. It cannot change a message either, because the changed message would no longer match the proof that came with it. Even with dishonest endpoints, no fabricated message can be accepted; whether messages keep arriving at all depends on at least one honest endpoint on each side.
Removing the middleman does not remove trust. It shrinks it to a short list you can read. For its messages to be genuine, an application using a channel trusts its own ledger, the CLPR software on both ledgers, the other ledger’s validators, the application on the other side, and the verifier the channel was created with. That last one deserves attention, because anyone can create a channel with any verifier they like. A channel existing does not mean its verifier is honest. Choosing a channel means choosing to trust its verifier, and applications, and whoever pays for their messages, are expected to check it before using the channel. Endpoints, and the accounts called connectors that pay for messages, are not on the list because they cannot forge anything; but messages only move while at least one honest endpoint on each side carries them and a connector pays.
Wider than a phone; scroll it sideways if you need to.
Check yourself: An endpoint's server is hacked and its private keys are stolen. What can the attacker now make Ledger B believe?
Nothing new. What Ledger B verifies is Ledger A’s validators’ signature, which the attacker does not have. The stolen keys let the attacker spend the endpoint’s prepaid transaction account and stop or slow its deliveries; any other endpoint can take over the delivering.
Section 5of 16
What makes CLPR different
One idea, proof instead of trust, has consequences all over the design. Set beside the usual approaches, they come out as six things CLPR does without.
Wider than a phone; scroll it sideways if you need to.
The first two are the point of the previous sections: no trusted party sits between the ledgers, and the receiving ledger does its own checking. The next two follow from them. There is no new token, because every fee, margin and fine is paid in a ledger’s native token; and there is no pool of user deposits, because what travels is a message, and the only funds the CLPR Service holds are connectors’ funds and endpoints’ bonds. The fifth is what makes CLPR a pattern rather than a pair of chains: any ledger can join once it has a CLPR Service, endpoints and verifiers for its proofs, and the protocol itself does not change. The sixth is the one to remember when something goes wrong: an endpoint that is hacked, bribed or switched off can delay messages, but it cannot forge or change one.
One more property is easy to miss. If both ledgers are of the kind that keeps working correctly even when some of their own participants misbehave, the messages between them inherit that property, provided the channel’s verifiers are correct and at least one honest endpoint on each side keeps them moving.
Check yourself: A connector, the account that pays for a message, is also an intermediary. Why is it not 'a party in the middle' in the sense that matters?
Because it cannot make either ledger believe anything. A connector approves and pays; it does not carry or verify a message. If it refuses to pay, the message fails with a reply saying so, and nothing false has been accepted anywhere.
Section 6of 16
The cast
Before watching a message travel, meet everyone it will pass through. Each card gives the everyday description first; open it for the precise one.
Application
The program that wants to talk to another ledger. It implements two callbacks: one for when a message arrives, one for when a reply comes back.
as the spec puts it
CLPR Service
The protocol's own part of each ledger. It keeps the outbound queues, checks the proofs, routes messages to applications, and handles the money.
as the spec puts it
Channel
A standing agreement between two ledgers to exchange messages, with its own numbered queue in each direction and a fixed way of checking the other side's proofs.
as the spec puts it
Verifier contract
The specialist that knows how to check one particular ledger's signatures and proofs. Each channel picks one when it is created and keeps that address for life, though the code behind it may be upgradeable.
as the spec puts it
Trust anchor
Who is allowed to sign for the other ledger right now. Stored per channel and only ever updated by a proof that the previous signers approved the change.
as the spec puts it
Connector
The account that pays. It approves a message on the sending side and pays for running it on the receiving side. If it breaks that promise, it is fined.
as the spec puts it
Endpoint
The program that carries messages between ledgers. It watches its own ledger, collects proofs, talks to endpoints on the other side, and submits what it receives as an ordinary transaction. It cannot forge anything.
as the spec puts it
Message
A parcel of bytes plus an address. Three kinds share one queue: data (what applications send), responses (the answer to a data message), and control (protocol housekeeping).
as the spec puts it
Bundle
A batch of messages that travels together with one proof covering the last of them.
as the spec puts it
State proof
A sealed receipt from a whole network, showing that a specific piece of data really is in its records.
as the spec puts it
Running hash
A hash of everything ever sent on a channel, updated with each message so that nothing can be inserted, removed or reordered unnoticed.
as the spec puts it
CLPR Service admin
The emergency brake. Can change the ledger's published limits, admit and evict endpoints, and close channels.
as the spec puts it
Wider than a phone; scroll it sideways if you need to.
Act III · One message, end to end
The journey, the running hash, the money, the failures
Follow one message there and back, then see what keeps it honest, who pays for it, and what happens when something breaks.
Section 7of 16
The message journey, step by step
Here is the whole thing at once, and it is the heart of this page. On the left, a ledger running the Hiero software. On the right, an EVM ledger whose validators seal blocks by a method called QBFT consensus. An application on the left sends the word “ping” to its twin on the right; the twin sends an answer back. Twenty-eight steps, two proofs, one reply. The switch at the top runs the same trip in the other direction, which proves itself with different cryptography.
Each piece of the diagram lights up as the message reaches it; that is the story.
One message, there and back: the 28 steps
Wider than a phone; scroll it sideways if you need to.
What you are looking at
Two ledgers. Each has an application, a CLPR Service with an outbound queue, a connector that pays, and a verifier that checks the other ledger's proofs. Endpoints carry messages between them: on the Hiero ledger every consensus node is one; on the EVM ledger it is a separate program. Press Play or step through with Next.
The application calls sendMessage on the CLPR Service
One function call on the application. It hands over four things: which channel to use, which connector is paying, who the message is for, and the message itself. The application does no cross-chain work of its own; it passes all of that to the CLPR Service and gets back a message id.
Channel ACTIVE; payload and queue-depth checks
Before accepting anything, the service checks the obvious. Does this channel exist and is it switched on? Is the message small enough for the other side to accept? Is the outbound queue already full? Any "no" and the whole transaction is rejected.
Per-connector queue quota
One busy payer could fill a shared outbound queue and starve everyone else on the channel. Giving each payer its own slice of the queue is one candidate fix; the EVM contracts already enforce one.
The connector authorizes the message
The connector is the account that pays. The service asks it, in effect: are you willing to cover this one? If it says no, nothing is sent.
A ConfigUpdate is queued first if this ledger's settings changed
If anything about this ledger's published limits changed since the last time this channel told the other side, a small housekeeping message is slipped into the queue ahead of yours. On a normal day nothing has changed and this step does nothing.
Message stored, running hash chained, next id advanced
The message is written into the outbound queue and given the next number in line. It is also folded into a running hash of everything ever sent on this channel, so the other side can later prove that nothing was inserted, removed or reordered.
The Hiero network signs the block root
The sending ledger's validators jointly sign the block the message landed in. It is a single aggregate signature produced by many nodes together.
A sync stream opens and BundleRequests are exchanged
The two endpoints keep a connection open between them. The receiving side says which message number it has reached, so the sending side knows exactly what to send.
The Hiero endpoint fetches the StateProof
The endpoint collects the receipt proving the message really is in the ledger's signed state. It only fetches this proof. It does not create it, and it could not forge it if it wanted to.
The BundleResponse travels down the stream
The message, together with its proof, travels down the open line to the other ledger's endpoint.
The EVM endpoint dry-runs the submission
Before spending money submitting anything, the receiving endpoint runs the whole verification locally as a dry run. If it would fail, nobody pays for it.
The bundle lands on the EVM CLPR Service
The endpoint sends an ordinary transaction on the destination ledger carrying the message and its proof. Everything from here until the reply is queued happens inside this single transaction.
The verifier checks the threshold signature and the Merkle paths
The destination ledger checks the source ledger's signature itself, against the identity it already trusts, and walks the proof back to the signed block. This is the step where the destination checks the source ledger's own signature itself, rather than relying on a relay's say-so.
Progress, size, replay and running-hash checks
Then the bookkeeping. Is this the next message in sequence? Have we seen it before? Does recomputing the running hash give the same answer as the proven one? Any mismatch and it stops here.
Connector resolved and the gas budget computed
The destination looks up the connector that agreed to pay and works out how much execution it can afford.
The application receives the message and answers it
The application on the other ledger finally receives the message, does its work and returns its answer. This is the moment the message has actually crossed; everything before it was transport.
The connector is charged and the submitter reimbursed
The connector pays for the execution that just happened, plus a little extra, and the whole amount goes to whoever submitted the transaction. That margin is why anyone bothers running an endpoint.
The reply is enqueued as a REPLY message
The answer is placed in the destination ledger's own outbound queue, numbered and folded into the running hash the same way the original was. Every application message that gets accepted produces exactly one reply.
The destination announces how far it has got
The destination records how far it has now received and acknowledged. The other side reads those numbers next time they talk and uses them to know what it can safely forget.
The EVM endpoint builds a QBFT state proof
Coming back, the proof works differently. This ledger's validators sign block headers directly, so the endpoint takes a header carrying those signatures plus a proof of the exact storage holding the reply.
Delivery to the Hiero endpoint, then pre-verification
The same discipline in reverse, on a later sync: the reply goes back down the line, and the receiving endpoint dry-runs it before paying to submit it.
Bundle submission on the Hiero ledger
The Hiero-side endpoint hands the reply to its ledger using that ledger's own transaction format rather than an EVM one.
QBFT committed seals checked against the trust anchor
The Hiero ledger checks the other ledger's validator signatures on that block header against the validators it has on record for this channel, and follows any change of validators since.
Account and storage proofs, then replay and running-hash checks
Then it checks the proof tying the reply to that exact signed block, and repeats the same sequence and running hash checks as the outbound leg. The proof technology differs; the rules do not.
Response ordering verified against the retained message
Replies have to come back in the same order the messages went out. If one arrives out of turn, the channel pauses rather than delivering it.
The original application is called back
The original application is called back with the message id, a status, and whatever the other side sent back.
Reply delivered; the original message deleted
Only now is the original message deleted from the outbound queue. It was deliberately kept until its reply arrived, so the ordering check just before had something to compare against.
Round trip complete
A message went to another ledger, ran there, and its answer came back. Each leg carried a proof of the other ledger's own consensus, checked on arrival by the channel's verifier, with no intermediary signer set in the middle.
The EVM application calls sendMessage on its CLPR Service
The same call, started from the other side. The application on the EVM ledger hands the four things (channel, connector, recipient, message) to its CLPR Service contract and gets back a message id.
Channel ACTIVE; payload and queue-depth checks
The same checks as the other direction, this time written in Solidity rather than living inside the node. Channel switched on, message small enough, outbound queue not full.
Connector queue quota checked
The connector's slice of the outbound queue is checked before it is asked to pay for anything.
The connector authorizes the message
The connector on this side approves the message. The same connector is registered on both ledgers under one identity, and that is what makes a channel work in both directions.
A ConfigUpdate is queued first if this ledger's settings changed
A housekeeping message carrying changed limits goes into the queue ahead of yours when something has changed, and is skipped when nothing has.
Message stored and MessageQueued(DATA) emitted
The message is written into the outbound queue and folded into the running hash. The service here is an ordinary contract, so storing your message also emits a log that anyone can read.
The EVM endpoint builds a QBFT state proof
This ledger's validators sign block headers directly, so the endpoint pairs a signed header with a proof of the exact storage slots holding your message.
A sync stream opens and BundleRequests are exchanged
One connection per sync, with the receiving side saying what it still needs. The transport does not care which way the message is going.
The BundleResponse with the QBFT proof travels to the Hiero endpoint
The bundle and its proof travel down the open line to the Hiero-side endpoint.
The Hiero endpoint pre-verifies the bundle locally
The receiving endpoint verifies everything locally first, so it never pays to submit something that will be rejected.
Bundle submission on the Hiero ledger
The Hiero-side endpoint hands the bundle to its ledger. From here to the application call, everything runs inside that one transaction.
QBFT committed seals verified against the trust anchor
The Hiero ledger checks the signatures in the block header against the validator list it holds for this channel.
EIP-1186 account and storage proofs verified
Then it checks the proofs that tie the contract, and the queue inside it, to that exact sealed block.
Progress, replay and running-hash checks
Sequence and running hash checks run exactly as on the other leg. The proof system changes; the rules about message integrity do not.
Connector resolved and the gas budget computed
The Hiero-side connector's balance sets the budget for the application call it is about to pay for.
The Hiero application receives the message and answers it
The Hiero application receives the message and returns its answer. This is the crossing point for this direction.
The connector is charged and the submitter reimbursed
The connector pays for the execution and the endpoint that submitted it is reimbursed, with a margin.
The reply is enqueued in the Hiero outbound queue
The answer goes into the Hiero ledger's outbound queue for this channel, numbered and folded into its running hash the same way the original was.
The Hiero side records how far it has received
The Hiero side records how far it has received and acknowledged; the other ledger reads those numbers on the next sync and uses them to know what it can forget.
The Hiero network signs the block root
The return leg is proved with the validators' joint signature over the block, the same mechanism the other direction used on its way out.
The Hiero endpoint fetches the StateProof for the reply
The endpoint fetches the proof tying the reply to that signed block, then sends it across; the destination dry-runs it before submitting.
The reply bundle lands on the EVM CLPR Service
The reply is submitted back on this ledger as an ordinary transaction, and its acceptance is announced on-chain.
The verifier checks the threshold signature and the Merkle paths
The verifier checks the joint signature and the proof paths against the identity on record for this channel.
Progress, replay and running-hash checks
Sequence and running hash are checked before any reply is handed to an application.
Response ordering verified against the retained message
The reply is matched against the oldest message still waiting for one. Out-of-order delivery pauses the channel instead.
The EVM application is called back
Your original contract is called back with the status and the other side's answer, closing the loop.
ReplyDelivered emitted and the original message deleted
One transaction does all of it: the service removes your original message from the queue, calls your contract back, then announces the delivery on-chain.
Round trip complete
The reverse journey closes the same way the forward one does, proved against each ledger's own consensus.
- Getting in line
- 1sendMessage()
- 2channel checks
- 3quota
- 4authorize()
- 5config sync
- 6enqueue
- Proving it happened
- 7TSS signature
- 8gRPC open
- 9fetch proof
- 10gRPC send
- 11pre-verify
- Crossing
- 12submitBundle()
- 13verifyBundle()
- 14hash chain
- 15gas budget
- 16onClprMessage()
- 17settle gas
- 18reply queued
- 19BundleProcessed
- Coming home
- 20QBFT proof
- 21gRPC back
- 22HAPI submit
- 23verify seals
- 24verify state
- 25ordering
- Closing the loop
- 26onClprResponse()
- 27delivered
- 28complete
- Getting in line
- 1sendMessage()
- 2channel checks
- 3quota
- 4authorize()
- 5config sync
- 6MessageQueued
- Proving it happened
- 7QBFT proof
- 8gRPC open
- 9gRPC send
- 10pre-verify
- Crossing
- 11HAPI submit
- 12verify seals
- 13verify proofs
- 14hash chain
- 15gas budget
- 16onClprMessage()
- 17settle gas
- 18reply queued
- 19sync data
- Coming home
- 20TSS signature
- 21fetch proof
- 22submitBundle()
- 23verifyBundle()
- 24hash chain
- 25ordering
- Closing the loop
- 26onClprResponse()
- 27ReplyDelivered
- 28complete
Three things stand out after watching it. Everything from step 12 to step 19 is a single transaction on the receiving ledger: if verification or the bookkeeping checks fail, none of it lands; if they pass, it lands whole, and an application that fails does not undo it, because the failure becomes the reply. Every data message that is accepted produces exactly one reply, whether the application liked it or not; the reply is what lets the sending ledger tidy its queue and check that answers come back in order. And the two directions prove themselves completely differently, with one joint signature going right and a sealed block header plus a storage proof coming back, under identical rules about numbering, hashing and ordering.
Wider than a phone; scroll it sideways if you need to.
Check yourself: Which steps could a dishonest endpoint change, and what would happen?
None of them, usefully. Steps 8 to 11 and 20 to 21 are the endpoint’s own work, but everything it produces is checked at steps 13 to 14 and 23 to 24 against signatures it cannot make. A tampered bundle is rejected and the endpoint has paid a transaction fee for nothing.
Section 8of 16
One proof for a whole batch
Step 6 of the journey mentioned a running hash. It is simple and it does a lot of work.
Every message added to a channel’s queue is given the next number in line and a running hash: a hash computed from the previous running hash and the message itself. (A hash is a short digest of some data; change one character of the data and the digest comes out completely different.) Change any message, drop one, or swap two, and every running hash after that point comes out different. The receiving ledger continues the chain from its own last running hash over the new messages it was handed and compares the final value with the one Ledger A’s validators signed. The numbers below are real SHA-256 hashes, computed in your browser.
Five messages, one chain of running hashes
| # | message | running hash after it | proven? | check |
|---|---|---|---|---|
| 1 | ping | …chain breaks here | - | |
| 2 | pay Bo 5 | …chain breaks here | - | |
| 3 | config update | …chain breaks here | - | |
| 4 | ping | …chain breaks here | - | |
| 5 | pay Cy 2 | …chain breaks here | 🔏 anchor |
🔏 anchor: …
This is why an endpoint can carry a batch of, say, forty messages with a proof covering only the last one. The receiver continues the chain from its last stored hash over the new messages it was handed, and if its last running hash matches the proven one, every message in the batch is proven too. The numbering does a second job: the receiver remembers the last number it processed and rejects a bundle whose first message is not the next number, so an old bundle cannot be delivered twice even though its proof is still perfectly valid. The EVM contracts are more lenient here: they skip leading messages they already have instead of rejecting the bundle.
Wider than a phone; scroll it sideways if you need to.
Section 9of 16
Who pays, and who gets paid
Somebody has to pay for all this. Delivering a message means an endpoint submits a transaction on the receiving ledger, and that transaction runs the application there. Submitting that transaction costs a fee, which ledgers call gas; endpoints are not charities.
CLPR introduces no new token. Instead it has a role called the connector: an account that agrees to pay. The same connector is registered on both ledgers under one identity. On the sending side the connector is asked, before the message is even queued, whether it will cover this one. On the receiving side the connector is charged for the gas the application actually used, plus a margin, and the whole amount goes to whoever submitted the bundle. That margin is what makes submitting bundles worth an endpoint’s while.
Wider than a phone; scroll it sideways if you need to.
A message arrives on Ledger B. Who pays whom?
Amounts are in "units" of Ledger B's native token. One unit buys 100,000 gas.
Happy path
charge 4.4 · balance 20
The connector’s approval on the sending side is a promise: my counterpart on the other ledger can pay for this, and I can pay for the reply. A connector locks up a deposit in advance, its stake. If the promise turns out to be false, the reply that comes home says so, and the fine is taken from that stake. Fines escalate, and repeated failures can get a connector banned from the channel, forfeiting whatever stake is left.
Applications choose their connector, and connectors can be as picky as they like: allow-lists, rate limits, charging a fee to the application. Several connectors can serve the same channel, and one operator can run connectors on many channels. Connectors, like applications, are expected to check a channel’s verifier before using it: a bad verifier puts the connector’s locked stake at risk.
Wider than a phone; scroll it sideways if you need to.
Check yourself: Who is paid when a message is delivered, and who is not?
Only the account that submitted the bundle on the receiving ledger, and only from the connector. Nothing goes to the sending side for this delivery, and the reply’s trip back is paid the same way, to whoever submits it on Ledger A; there is no protocol treasury, and the endpoint that did the sending work earns nothing directly. Endpoints are expected to prefer partners that bring them messages in return.
Section 10of 16
What can go wrong
A protocol is defined as much by what it does when things go wrong as by what it does when everything works. Pick a failure and see what CLPR does.
Pick a failure. What does the protocol do?
The application on the other side crashes
The connector was never registered on the other side
The connector on the other side has run out of funds
An endpoint changes a message in transit
An endpoint re-submits an old bundle
All the endpoints on one side go offline
The other ledger goes down entirely
Replies come back in the wrong order
The message is larger than the other side accepts
Every endpoint on the other side was replaced and nobody knows the new addresses
The verifier turns out to be buggy or compromised
A ledger changes how its proofs look
A ledger's own validators are compromised
Notice a pattern. A bundle that fails its checks (its proof, numbering or hashes) is rejected, changing nothing: the channel stays open and the next honest bundle goes through. A failure in a single message, such as an unknown or underfunded connector or an application that errors, becomes a failure reply and the rest of the bundle carries on. One failure is treated as a sign that something is broken rather than a passing glitch: replies arriving out of order. For that one, the channel is paused instead of guessing. Endpoints can only ever cause delay. The only failures that fine anyone are a connector failing to pay for a message as promised: the fine is taken from the connector’s locked stake.
Wider than a phone; scroll it sideways if you need to.
Act IV · What you can build
What people build with it
The four patterns the protocol was designed around, the shapes of network that pairs of ledgers can form, and who runs what.
Section 11of 16
Four things people build with it
Everything so far is plumbing. Here is what the design anticipates people building on it; it outlines these patterns only at a high level, and none is specified yet. A message in CLPR is just bytes with an address, and every data message gets exactly one reply (as long as the channel and its endpoints keep working), so the same primitive could serve four quite different jobs.
Wider than a phone; scroll it sideways if you need to.
Remote smart contract call
A contract on one ledger calls a proxy, which records the call. An endpoint carries it across, the proxy on the other ledger invokes the target contract, and the result comes back the same way. Applications have to be written for answers that arrive later, not in the same call.
Escrow, mint, then burn
Assets are locked on the source ledger, then minted on the destination. If minting succeeds the locked assets may be burned; if it fails they are released. Needs atomic semantics and a common asset standard.
N-ledger atomic swap
Several ledgers make state changes tied together by two-phase commit: each enters a ready-or-roll-back state, and if any one fails, all roll back. Every participating ledger must understand the others' commit messages.
Native Hiero asset management
Hiero tokens, fungible and non-fungible, handled across Hiero networks by the messaging layer directly, with no smart-contract proxies in between. The design outlines this in one sentence; it is not yet specified.
When several channels exist between the same two ledgers, for example one per Ethereum commitment level, the application picks one at send time by its own needs: a price feed may accept the risk of a reorganisation for speed, a high-value transfer waits for finality. CLPR imposes no default.
The third pattern is worth watching, because it shows what the protocol does and does not do. Three ledgers are meant to change together or not at all. CLPR carries the messages and a reply for each; the decision to commit or roll back lives in the application that started the swap. The simulation draws one way such an application could use the protocol; the choreography is the site’s illustration, and the pattern itself is only outlined in the design.
Three ledgers change together, or not at all
Wider than a phone; scroll it sideways if you need to.
Check yourself: Why must the swap application, and not CLPR, keep the tally of who is ready?
Because CLPR knows nothing about swaps. It knows messages, replies, proofs and payment. Tying three ledgers’ changes together is a meaning the application gives to its messages, and only the application can decide what “everyone is ready” means for it.
Section 12of 16
Shapes of a network
A channel always joins exactly two ledgers. That sounds limiting. It is the opposite: because every pair agrees on its own, with its own queues and a verifier chosen for it on each side, any shape you can draw from pairs is a shape you can build, and the protocol puts no trusted party in the middle of any pair.
Wider than a phone; scroll it sideways if you need to.
Wider than a phone; scroll it sideways if you need to.
The one thing to keep straight is that CLPR itself knows only the pairs. Nothing in the protocol forwards a message from one ledger to a third through a second. In the star, a message from one spoke to another has no path, unless an application on the hub receives it and sends a new message of its own to the other spoke, under its own connector and its own channel. That is a perfectly good thing to build; it is an application, not a protocol feature.
Shapes you can build from pairs
Wider than a phone; scroll it sideways if you need to.
The pair that matters most to many organisations is a private network and a public one. A ledger that does not want to expose any infrastructure lists its endpoints without an address to dial. Its endpoints then always dial out and are never dialled, and once the connection is open, messages flow both ways over it. That is how a private enterprise network talks to a public one without opening a door.
Wider than a phone; scroll it sideways if you need to.
Check yourself: Two ledgers both have a channel to the same third ledger. Can one send the other a message?
Not through CLPR alone. There is no channel between them, and CLPR defines channels only between two ledgers. Either they open their own channel, or an application on the third ledger receives the message and sends a new one on, as its own message with its own proof and its own payer.
Section 13of 16
Who runs what
CLPR is operated by people in six roles, and the design has a quiet rule about them: whoever would lose money is whoever does the checking.
Wider than a phone; scroll it sideways if you need to.
| Role | What they do | What they risk |
|---|---|---|
| End user | Uses applications. Evaluates an application before using it and watches for degraded service; never touches the protocol directly. | Application bugs, poor channel or connector choices, a channel closed while messages are in flight, and finality risk if a verifier accepts proofs below finality. Escrowed assets should be settled before stopping. |
| Application developer | Sends messages and handles the responses in callbacks, naming a channel and a connector on every send. Keeps both configurable, watches connector health and channel status, and migrates when a proof format changes. | Every cross-ledger payload is untrusted input; payloads sit on chain in plaintext unless the application encrypts them; a compromised verifier can mean direct loss of assets. |
| Connector operator | Often also creates the channel: deploys a verifier, registers the channel, then registers as a connector on both ledgers. Keeps a balance to pay for execution and a locked stake that covers fines; may run allow-lists and rate limits. | An empty balance fails messages and slashes the stake with escalating penalties; a lapsed registration fails them too; removal is blocked while messages are in flight. |
| Verifier developer | An off-chain role with no protocol identity: writes the contract that checks one ledger's proofs. Ledger implementers, connector operators, application developers with high-value flows and auditors all have reasons to. | Proof format changes need new implementations; an upgrade key on a verifier is a single point of compromise; the protocol pays nothing for maintenance. |
| Endpoint operator | On Hiero, nothing: every consensus node is an endpoint automatically. Elsewhere, registers with a bond, is admitted by the service admin, serves every channel on the service, and pre-funds the account that submits bundles. | Invalid, failed or duplicate submissions cost unreimbursed fees; misbehaviour means eviction, with the bond returned in full. |
| CLPR Service admin | Broad but only protective powers: adjusts the ledger's published limits, admits or evicts endpoints, closes channels and, where the service has a kill switch (the EVM contracts do), turns it on or off. Cannot create channels, register connectors or take part in the economics. | Abuse of power, mitigated by governance; inaction, since a compromised channel left open keeps being exploited; and no in-protocol incentive, a known gap between responsibility and motivation. |
A few things follow from the table. The admin, the only role with any special power, has the least incentive to watch closely, a known gap between responsibility and motivation. The verifier developer is not registered anywhere in the protocol and holds no stake, yet every channel’s safety rests on the verifier they wrote. And the connector operator is expected to be the careful one, because their locked stake is at risk if the verifier is compromised.
The roles rarely act alone. Four stories show them working together: setting up a new route between two ledgers, upgrading when a ledger changes how its proofs look, responding to a verifier that turns out to be compromised, and a connector withdrawing while messages are still in flight.
Four stories: the roles working together
Wider than a phone; scroll it sideways if you need to.
Before anything happens
Press Next to walk through the 4 steps. The roles that act in each step light up above.
A verifier developer publishes and audits a verifier for the target proof system.
A connector operator evaluates it, deploys it, registers the channel on both ledgers, and registers as a connector on both sides.
An application developer evaluates the channel and the connector and integrates them.
End users use the application; the trust chain is active from top to bottom.
Before anything happens
Press Next to walk through the 6 steps. The roles that act in each step light up above.
The source ledger announces a proof format upgrade.
A verifier developer publishes a verifier for the new format.
A connector operator creates a new channel with it and registers as a connector.
Application developers migrate to the new channel.
The source ledger switches formats; the old channel's verifier stops working.
The service admin closes the old channel. The source ledger keeps the old format alive long enough for the migration.
Before anything happens
Press Next to walk through the 5 steps. The roles that act in each step light up above.
A vulnerability is discovered and a security advisory issued.
The service admin closes the affected channels; their queues drain.
The verifier developer publishes a patched implementation.
Connector operators create new channels with the patched verifier.
Application developers migrate. The window of exposure is between discovery and close.
Before anything happens
Press Next to walk through the 4 steps. The roles that act in each step light up above.
The connector operator updates its authorization contract to reject all new messages.
Application developers switch to another connector or notify their users.
Messages already queued complete normally.
Once every in-flight message has settled, the operator removes the connector and recovers its funds.
Check yourself: A verifier is found to be compromised. Who acts first, and what is the window of danger?
The verifier developer, by issuing a security advisory; the service admin then closes the affected channels so no new messages are accepted while the ones in flight finish. The window of danger is the time between the vulnerability being discovered and the channels being closed. Then the verifier developer publishes a fix, connector operators open new channels with it, and applications move over.
Act V · The edges, and the lab
Adding ledgers, limits, and where CLPR lives
How a new kind of ledger joins, what CLPR deliberately does not do, and where the code and the people are.
Section 14of 16
Adding a new kind of ledger
CLPR is a pattern, not a pair of chains. Adding a new kind of ledger needs no change to the protocol or to existing implementations; anyone can deploy the new verifier on a ledger it connects to and register a channel there. It needs three things. First, a CLPR Service on the new ledger. Second, endpoints that can build proofs in the new ledger’s format. Third, a pair of verifiers: one runs on the new ledger and checks the existing ledger’s proofs; the other runs on the existing ledger and checks the new ledger’s proofs.
Adding a new ledger type
Wider than a phone; scroll it sideways if you need to.
The pattern that makes CLPR extensible
The CLPR Service implementation on existing ledgers does not change when a new one joins; they only gain a verifier and a Channel. The alignment between the new ledger's endpoint (which builds bundles in that ledger's format) and the verifier it ships for other ledgers (which reads that format) is the whole trick.
Implement a CLPR Service and CLPR Endpoints for the new ledger type
The Service can be native to the node or a smart contract; either way it must conform to the behavior in the specification. The Endpoints read the new ledger's CLPR state, build state-proven bundles in the ledger's own data format, and speak the common sync protocol.
Implement a Hiero verifier that runs on the new ledger
So the new ledger can check proofs coming from Hiero.
Implement a verifier for the new ledger that runs on Hiero
So Hiero can check proofs coming from the new ledger. This verifier also translates the new ledger's bundle format into what the receiving Service expects.
Deploy each verifier to the opposite network
Verifiers are ordinary contracts on the receiving side. Deploying one is permissionless.
Set up a Channel between the two CLPR Services
Commit on both ledgers, then reveal on both, naming the verifier each side will use. The verifier's address is fixed for the channel's lifetime, though the contract behind it may be upgradeable.
Share each network's endpoints with the other
The endpoint list is on-chain state on each side and is proved into the channel at creation; later changes travel inside bundle proofs.
Set up a common Connector bonded to the Channel
The same connector identity is registered on both ledgers: it authorizes on the sending side and pays on the receiving side.
Deploy applications that use the Connector and Channel
Applications implement two callbacks and never touch proofs, relays or verification.
The reason this works is that the CLPR Service never looks inside a proof. It hands the proof to the channel’s verifier without reading it, and gets back a list of checked messages written the same way for every kind of ledger. Whatever the new ledger’s cryptography looks like, it is contained inside its verifier and its endpoints, and the rest of the protocol is untouched.
Today the kinds of ledger with a verifier are these. Two are fully documented and built; the others exist as code without a document, or as a stand-in for testing.
| Kind of ledger | What its proof is | Its CLPR Service | Its endpoints | Status |
|---|---|---|---|---|
| Hiero networks: Hedera and private HashSpheres | A joint threshold signature by the network's validators over a summary of its state, plus the paths down to each record it proves | Built into the consensus node | Every consensus node is one | documented and built |
| EVM ledgers running QBFT | A block header carrying the validators' seals, plus a proof of the storage slots that hold the data | Solidity contracts | The endpoint program | documented and built |
| Ethereum mainnet | Sync-committee signatures checked by a light client | Solidity contracts | None: the endpoint program does not support it | verifier code only |
| Sei, a CometBFT network | CometBFT validator signatures (Ed25519) | Solidity contracts | The endpoint program | verifier code only |
| Avalanche | Not implemented; a mock verifier stands in | Solidity contracts | None: the endpoint program does not support it | stand-in only |
Section 15of 16
What CLPR does not do
A page like this should be as clear about limits as about mechanisms.
Delivery depends on endpoints. If nobody runs an endpoint for a channel, messages sit in the queue. Nothing is lost or faked; nothing moves either.
Nothing is secret. Message contents sit on both ledgers in plain view. The protocol guarantees that a message is authentic and unaltered, not that it is private. Applications that need confidentiality must encrypt before sending; even then, when a message was sent, how big it is and who sent it stay visible.
Authentic is not the same as safe. CLPR proves a message really came from the other ledger. It says nothing about whether the message is sensible. An application must treat everything that arrives from across the water as untrusted input, exactly as it would treat a call from a stranger.
Wider than a phone; scroll it sideways if you need to.
A channel is no safer than its verifier. A channel’s safety rests on both ledgers’ consensus, both CLPR Services and its verifier, and its payments on connectors. Of these, the verifier varies most: anyone can create a channel with any verifier, and a verifier behind an upgradeable proxy can have its logic replaced later by whoever holds the upgrade key. The protocol’s own checks catch a verifier bug that garbles messages, because the running hashes will not match; they cannot catch a lying verifier that fabricates messages and matching running hashes. Vetting verifiers, and who can upgrade them, is human work.
Wider than a phone; scroll it sideways if you need to.
Some ledgers can rewrite recent history. On some networks a block is not final the moment it is made; for a while the network can still drop it and replace it. A verifier that accepts a block that fresh risks a “phantom message”: one delivered on this side whose sending block the source ledger later threw away. How final a block must be is a property of each channel’s verifier, and CLPR does not check it. For anything valuable, use a channel whose verifier accepts finalized blocks only; two channels between the same ledgers can differ.
Wider than a phone; scroll it sideways if you need to.
Some things are not settled yet. These are the open questions:
- Anyone can register a channel claiming any chain id. Channel creation needs nobody's permission, so anyone can construct a ledger configuration with any chain id they like. An application has to check for itself that a channel really leads to the ledger it intends; a channel's existence proves nothing about its peer.
- Open endpoint registration rests on admin curation. Where anyone can register an endpoint, keeping the list honest rests mainly on the admin admitting each one; the bond adds friction but is not sized against attack costs on any particular chain. Peers should be picked with some randomness so no two endpoints pair up for good. On Hiero the network's own stake-weighted consensus covers this.
- A verifier behind an upgradeable proxy can change under a channel. The verifier's address is fixed for a channel's life, but the contract at that address may be a proxy whose logic can be replaced without the protocol noticing. The protocol allows it; anyone evaluating a channel should check whether its verifier is a proxy and who holds the upgrade key.
- How large a connector's stake must be is not yet quantified. A connector's locked stake must cover the worst case: on the receiving side, the cost of running in-flight messages from a connector that has run dry; on the sending side, the fines for failed deliveries. A bond that is too small lets an attacker drain endpoints of more execution cost than the fines can repay. The minimum is a design parameter still to be quantified before production.
- One connector could fill a shared queue. A single connector could approve enough messages to fill a channel's queue and block everyone else on it. Candidate answers: money escrowed per message and returned when the reply arrives, a per-connector share of the queue, or prices that rise as the queue fills. Unresolved before production.
- The admin has duties but no reward. The service admin must close a compromised channel promptly and gains nothing in the protocol for doing so: a known gap between responsibility and motivation.
Beyond these, the authors keep a separate list of possible changes they have considered and not decided.
The protocol is young. The initial text is expected to change further to polish out rough edges; its major changes so far are recorded as dated decision records saying what was decided and why.
Section 16of 16
Where CLPR lives, and where this leaves you
CLPR is a set of ideas and also a set of files. Everything the lab publishes about the protocol is one of four kinds of thing. The specification says what must happen. The CLPR Service, the on-ledger part that holds every channel and queue, is built twice: once into Hiero nodes, once as contracts for EVM networks. The verifiers plug into a service. And the endpoint is the program that runs off the ledgers and carries bundles between them.
Wider than a phone; scroll it sideways if you need to.
Everything CLPR is made of. Tap a piece.
Wider than a phone; scroll it sideways if you need to.
The specification
Where: LFDT-CLPR/clpr-spec
The rulebook every other piece must follow. Two documents: a design document that explains the why (trust model, layers, roles, recovery) and a protocol specification that fixes the what (wire formats, state, algorithms, a pseudo-API). Alongside them, one folder per supported proof system saying exactly how that ledger's proofs are built and checked, and the decision records that explain the main changes made to the text.
Pinned: design document · protocol specification · verifiers/ · ADR/ · LICENSE · Labs charter (PDF)
CLPR Service, native (Hiero)
Where: hiero-ledger/hiero-consensus-node
On Hiero networks the CLPR Service is built into the node software itself. Its queues and channels live in the node's own state tree, which is what makes them provable with the network's own signature. Contracts reach it through a fixed system address.
Pinned: org profile: initial OSS · design §3.1.0
CLPR Service, contract (EVM)
Where: LFDT-CLPR/clpr-smart-contracts
On EVM ledgers the CLPR Service is a set of Solidity contracts. One immutable front door holds all the state and forwards each call to a module that knows how to handle it: channels, messaging, bundles, connectors, administration. Built and tested with Foundry.
Pinned: ClprService.sol · docs/architecture.md · IClprService.sol · README
Verifier contracts
Where: LFDT-CLPR/clpr-smart-contracts/src/verifiers
The specialists that check another ledger's proofs. Each channel names one when it is created and keeps that address for life, though the contract behind it may be upgradeable. Two have verifier specifications in the specification repository: one for Hiero networks (checking the network's joint threshold signature) and one for EVM ledgers running QBFT (checking validator seals on block headers plus storage proofs). The repository also carries verifier code for other consensus families.
Pinned: HieroVerifier.sol · QBFTVerifier.sol · IClprVerifier.sol · spec verifiers/ · design §3.1.5
Endpoint (relay) for EVM ledgers
Where: LFDT-CLPR/clpr-endpoint
The endpoint program for EVM ledgers. It watches its own ledger's CLPR Service, talks to endpoints on the other side over gRPC, builds proofs of what its ledger has queued, dry-runs every bundle it receives, and submits the good ones as ordinary transactions. Its keys pay its own transaction fees and identify it to other endpoints over mutual TLS when the operator enables it; none of them can make a ledger accept a message.
Pinned: README · docs/architecture.md · docs/sync-protocol.md · relay-config-example.yaml
Endpoints on Hiero
Where: part of the native implementation
On a Hiero network there is no separate endpoint program: every consensus node is automatically an endpoint, and the list of them is kept up to date by the network itself. The node builds and signs the proofs as part of producing blocks; the endpoint only fetches the finished proof and carries it.
Pinned: design §3.1.2 · verifiers/hiero/state_proof.md
The sync protocol
Where: spec §1.5; clpr-endpoint proto + grpc modules
How two endpoints talk: specified to run over mutual TLS, each sync is one stream for one channel, on which each side says how far it has got and receives the next messages after that point, up to the bundle limits, together with the proof. Requests are cheap and unproven; bundles are proven. Nothing is delivered that the receiver did not ask for.
Pinned: spec §1.5 · ADR 2026-07-14 · clpr-relay-proto · ClprSyncService.java
Connector contracts
Where: IClprConnector (EVM); native registration on Hiero
The account that pays, present on both ledgers under one identity. On the sending side its contract decides whether to approve a message; on the receiving side its balance pays for running the message and its locked stake is what gets fined if it breaks its promise. Anyone can register one, on any channel, with a balance and a stake.
Pinned: IClprConnector.sol · design §3.3.1 · spec §6.3
Applications
Where: IClprApplication; anything you deploy
Your program. It calls one function to send and implements two callbacks to receive: one for an incoming message (whatever it returns becomes the reply) and one for the reply to a message it sent. It chooses, and should vet, the channel and the connector for each message; proofs, endpoints, verification and payment are handled below it.
Pinned: IClprApplication.sol · E2EApplication.sol · design §3.4 · design §2.4 · IClprService.sol
The lab: LF Decentralized Trust
Where: LFDT-CLPR/governance and .github
Where the specification, the smart contracts and the EVM endpoint are governed: an incubation space under the Linux Foundation's LF Decentralized Trust, offered by the Hedera Governing Council and open to anyone under the Apache License 2.0 with a Developer Certificate of Origin sign-off on every contribution.
Pinned: organization profile · teams.yml · Labs charter (PDF)
The two CLPR Services have no code in common. Both are written to the same text, down to the exact bytes a message is written as and the exact order of the checks, and both must conform to it; the contracts repository keeps a written list of where its code currently differs, and some of those differences are being settled by updating the text.
| Repository | What it holds |
|---|---|
| LFDT-CLPR/clpr-spec | Protocol specification (clpr-service.md, clpr-service-spec.md), ADRs and verifier documents. The primary source for every protocol claim on both pages. |
| LFDT-CLPR/clpr-smart-contracts | Solidity CLPR Service, logic modules and Verifier contracts for EVM ledgers. Source of the application interfaces and of every pinned code link on the developer page. |
| LFDT-CLPR/clpr-endpoint | Java CLPR Endpoint (relay) for EVM ledgers: gRPC sync, proof construction, bundle submission. Source for the endpoint and sync-protocol sections. |
| LFDT-CLPR/governance | Lab governance: LF Decentralized Trust Labs charter, teams and repository permissions. Source for the governance section. |
| LFDT-CLPR/.github | Organization profile README: lab scope, terminology, the four layers and the extension process. Source for the 'what CLPR is' framing and the LFDT section. |
The ideas come from earlier proposals for cross-ledger communication and from a practical need: Hiero-based networks, public ones such as Hedera and private ones called HashSpheres, needed fast, asynchronous messaging between them that stays correct even when some participants misbehave. Under its agreement with the Hedera Governing Council, Hashgraph wrote the initial text and built initial versions of the three pieces of software above; the endpoint is a prototype. CLPR is now an LF Decentralized Trust lab, part of a Linux Foundation project whose mission is to support development of very early open projects, under the technical oversight of the LF Decentralized Trust’s Technical Advisory Council; the Council undertook to donate the CLPR brand once the lab was accepted. The CLPR Service built into Hiero nodes is specified by HIP-1535, whose status is Approved, and is an opt-in service: networks that do not enable it are unaffected.
If you remember six things, remember these.
- A ledger is a shared record many machines keep in sync, and a network can jointly sign a proof that a particular line is in it.
- Two ledgers cannot see each other, and the usual fix, a trusted party in the middle, makes every message only as safe as that party.
- CLPR replaces the party with a proof: the receiving ledger checks the sending ledger’s own validators’ signature through the channel’s verifier, and trusts that verifier and the CLPR Service on each side to be correct.
- Endpoints carry proofs, but nothing they carry is taken on their word. They can delay; they cannot forge. Whether a message is genuine is decided on the ledgers (safety); whether it arrives at all depends on endpoints (liveness).
- Messages are numbered and chained into a running hash, so one proof covers a whole batch and nothing can be inserted, dropped, reordered or replayed.
- Connectors pay, endpoints are reimbursed with a margin, and a connector that breaks its promise is fined. Every accepted data message gets exactly one reply.
Wider than a phone; scroll it sideways if you need to.
The developer page →
From zero to the full protocol: the API, the 28 steps in protocol terms, bundles and verification, channels, endpoints, verifiers, connectors, recovery, the reference implementations, and how to contribute.
The lab on GitHub →
The specification, contracts, endpoint and governance repositories, with their commits listed at the bottom of this page.
Repositories and commits
The LFDT-CLPR repositories and commits this explainer describes, as of 2026-11-02.
Four sections contain the site's own illustrations rather than statements about CLPR: section 2, section 3, section 11 and section 12. Everything else describes the commits below.
| Repository | Commit | Committed | Used for |
|---|---|---|---|
| LFDT-CLPR/clpr-spec | 945082d | 2026-08-31 | Protocol specification (clpr-service.md, clpr-service-spec.md), ADRs and verifier documents. The primary source for every protocol claim on both pages. |
| LFDT-CLPR/clpr-smart-contracts | 276c8d5 | 2026-09-01 | Solidity CLPR Service, logic modules and Verifier contracts for EVM ledgers. Source of the application interfaces and of every pinned code link on the developer page. |
| LFDT-CLPR/clpr-endpoint | 2ccd48d | 2026-09-01 | Java CLPR Endpoint (relay) for EVM ledgers: gRPC sync, proof construction, bundle submission. Source for the endpoint and sync-protocol sections. |
| LFDT-CLPR/governance | 1447ae0 | 2026-10-28 | Lab governance: LF Decentralized Trust Labs charter, teams and repository permissions. Source for the governance section. |
| LFDT-CLPR/.github | 528e9c0 | 2026-10-28 | Organization profile README: lab scope, terminology, the four layers and the extension process. Source for the 'what CLPR is' framing and the LFDT section. |