Introduction

This is the technical report for the Catalyst fund13 project “EUTxO L2 Interoperability”. It will be used to gather and introduce background information, but also as a delivery artifact for the various milestones.

The full list of milestones can be found here and the corresponding chapters in this document will contain documentation, instructions and links to other materials to reproduce or use our results in further work.

Background

Relevant research

Reading list

Hash Timelock Contracts (HTLC)

Setting up an HTLC allows the sender to lock an asset to be spent “accordingly” or it allows them to get back their funds after a timeout. Not much scripting is required for this construction, hence it is popularly used in Bitcoin Lightning to effectively forward payments between channels.

In Bitcoin Lightning, HTLCs are also used to swap into and out of lightning channels from the Bitcoin main chain. These atomic swaps are called Submarine Swaps and are fully trustless (no custody, no counterparty risk) because they share the same underlying chain / security model (= Bitcoin).

Adaptor signatures

Originating from ideas on Scriptless scripts where correct execution of scripts is captured by the validity of digital signatures (elliptic curve based schemes), so-called adaptor signature schemes can be used to reveal information through the actual signature. Verifiably Encrypted Signatures (VES) are a generalization of this concept onto both Schnorr and ECDSA signature schemes.

Related work about cross-chain atomic swaps between Bitcoin and Monero suggests that adaptor signatures can be used to realize unlocking on even very constrained target chains (Monero). We are in a much more comfortable position of very scriptable ledgers.

Quite low-level treatment on the signature schemes: https://medium.com/crypto-garage/adaptor-signature-schnorr-signature-and-ecdsa-da0663c2adc4

Milestone 1

Consists of two parts

  1. HTLC prototype of payment between two L2s
  2. Transaction design for ad-hoc ledgers

HTLC payment

Example workflow of a payment of some $USDM from Alice to Bob via one intermediary Ida using Hash-Time-Locked Contracts (HTLC).

The topology of the involved L2s is not further specified here, but could be for example two Hydra heads between Alice-Ida and Ida-Bob, or a two-party head beween Alice-Ida and both, Ida and Bob being participants of a Midgard optimistic rollup. Even multi-party heads where multiple intermediaries could share the collateral across multiple HTLC outputs are thinkable, but that would need further investigation how we can guarantee collateralization across multiple outputs.

HTLC Design

The HTLC is implemented as a single validator, with two possible redeemers, Claim and Refund. No validation is run during the Lock operation.

UTxOs Specification

HTLCUtxo

Address

  • Script address

Datum

  • hash: ByteString
  • timeout: PosixTime
  • sender: VerificationKeyHash
  • receiver: VerificationKeyHash

Value

  • min ADA
  • offered tokens

Transactions

Lock Funds

Creates an HTLCUtxo containing the offered tokens. The datum specifies the sender and receiver Verification keys for future authetication, as well as the timeout in posix time and the hash of the secret needed to claim the funds.

In step 1 of our example, Alice would execute this transaction and specify herself as the sender, Ida as the receiver, a timeout sufficiently in the future and the hash shared by Bob. In step 3, Ida would execute this transaction and specify themselves as the sender, Bob as the receiver, a timeout slightly lower than the one Alice specified and the same hash used in step 1.

The lower timeout is needed to avoid a situation where Bob claims the funds in Head B and Ida is unable to claim their share in Head A.

Lock funds into HTLC

Claim Funds

Consumes a HTLCUtxo with the Claim redeemer, providing the preimage of the stored hash. This transaction must be submited before the timeout and must be signed by the receiver.

In step 4, Bob uses the preimage that they generated in step 0 to claim the funds. In step 6, Ida uses the preimage that they learned from Bob’s transaction to unlock the funds locked by Alice.

Claim funds from HTLC

Refund

Consumes a HTLCUtxo with the Refund redeemer. This transaction must be submited after the timeout and be signed by the sender.

Refund funds from HTLC

Ad-hoc ledgers

The State Machines across Isomorphic Layer 2 Ledgers paper describes a solution for implementing atomic transactions performed across multiple L2 ledgers. By the paper, this is achieved by the verify→perform mechanism.

The verify→perform mechanism

Lets analize a simple example with just two Hydra heads as the L2s.

Let A, B be Hydra heads. An atomic transaction is a process involving a sequence of two transactions per head, named verifyX and performX for head X ∈ {A, B}. The goal would be to transfer assets from A to B, avoiding inconsistent and non-reversible states.

The purpose of verifyX is to “simulate” the corresponding action to be performed in X. If verifyX succeeds for each X, it means that performX is safe to execute.

In simple terms, we first verify that the action to be taken in each head is doable (inputs could be spent, minting/burning validates successfully if any), and only then are the actions performed in each head. If performX for each X is successful, then the assets transfer from A to B is completed.

But, how to verify a future perform without executing it? In the verify step, the protocol does not directly produce the final outputs of the transfer. Instead:

  • The full body of the intended perform transaction (the “original transaction”) is embedded in the verify transaction’s somewhere (or maybe a hash of it).

  • verify ensures that its own inputs match those expected by the original transaction, and that all validation conditions (scripts, minting/burning policies) to produce the outputs (held in the embedded transaction) can be satisfied.

  • Because outputs are not yet created, irreversible actions like actual burning or final distribution do not happen at this stage.

  • Once verify has succeeded in both heads, the perform transaction does what the stored original body says, burns any temporary tokens, and creates the final outputs exactly as pre-agreed.

This mechanism implies that verify should be reversible. The paper includes situations where the verify step must be reversible, for example, transferring assets from A to B without an intermediary liquidity provider. This would involve burning them from A and minting them in B. If verifyA succeeds and verifyB doesn’t, we must be able to recover those assets in A. But if intermediaries provide the liquidity on the destinations ledgers, this might not be needed. Further investigation is needed to determine if this is the case.

In any case, NFTs are not considered in this mechanism. Only for ADA and fungible tokens. Extra policy engineering is needed to support NFTs.

In scenarios where one of the parties in charge of doing perform stalls the protocol flow by not doing it, a merge-transaction is needed to resolve disputed UTxOs, supported by other safety measures like collateralization.

The UTxOs subject to the verify→perform mechanism are called wrapped UTxOs, whose set defines the ad-hoc ledger Lₚ. Each head will contain a replica of the Lₚ. For the given use case of AB transfer

  • Replica R₀ in A contains Lₚ-wrapped UTxOs that include the actual asset being moved. These UTxOs are locked under the Lₚ validator.
  • Replica R₁ in B contains Lₚ-wrapped UTxOs that include the intermediary collateral. Locked under the same Lₚ validator.

Atomicity is enforced by making every Lₚ state change happen on both replicas (or none), so those two local views stay semantically equal even though the concrete UTxOs represent different things (assets to move on A vs collateral on B). In other words, both replicas UTxO set being semantically equivalent is the invariant that ensures atomicity. Divergent replicas states mean a liquidity trap.

The entities in charge of coordination of the verify→perform sequence on both heads is called intermediaries. They co-sign reversible verify transactions to confirm that inputs, witnesses, and policies are valid without committing to irreversible changes.

Intermediaries generate a pre-collected aggregate signature –a single signature assembled from all intermediaries’ keys– which will later authorize the irreversible perform transactions.

Intermediaries also post collateral, locked under the Lₚ validator at head B, equalling the value of the secured wrapped UTxOs at head A, needed for asset transfers. In a simple case of AB transfer with just one intermediary, the intermediary posts the collateral in R₁ replica and receives the same amount in R₀ replica.

How to verify a future perform without executing it?

The verify step stages a reversible transaction that proves the perform step can succeed. This is achieved by:

  • Collecting all relevant inputs: wrapped UTxOs from both replicas (assets in Head A, collateral in Head B).
  • Running all on-chain validation scripts: minting/burning, spending conditions, exactly as they would be in perform, but with outputs locked to an intermediate state rather than the final recipient.
  • Minting temporary proof tokens: these attest that the inputs passed validation and can be spent in perform.
  • No irreversible actions: assets are not actually moved to the destination or destroyed. Instead, they are locked in a way that can be undone if the other head’s verify fails.

This process guarantees that if both heads succeed in verify, the perform transactions can later be executed with no risk of failure, while still allowing reversibility if one side cannot verify.

Basic Use Case Specification

Transfer from Alce in Head A → Bob in Head B (with intermediaries set 𝙄 = {Ida})

Participants

  • Alice in Head A: sender of asset X
  • Bob in Head B: receiver of asset X
  • 𝙄 = {Ida}: intermediaries present in both heads; hold collateral; co-sign atomic steps (Ida is the only intermediary in this case)

Wrapped UTxO Datum Specification

  • owner (Address)
  • Kᵢ: aggregated public key of all intermediaries. For enforcing multisig control from the intermediary set.
  • nonce (Integer): random value generated at setup to uniquely bind the UTxO to a specific ad-hoc ledger instance.
  • perform tx body hash (Hash): hash of expected perform tx body to be executed after verify.

Step-by-Step Flow

  • Wrap assets to transfer + collateral

    • Head A: Alice locks asset X in Lₚ script → creates wrapped UTxO in replica R₀.
    • Head B: Ida locks their share of collateral in Lₚ script → creates wrapped UTxOs in replica R₁.
  • verifyA (Head A)

    • Consumes Alice’s wrapped UTxO, produces a staging UTxO (same assets, reversible, with proof of validity).
    • Ida’s signature is made.
  • verifyB (Head B)

    • Consumes collateral UTxOs, produces staging collateral UTxO (same assets, reversible, with proof of validity).
    • Ida’s signature is made.
  • Collect perform signatures

    • Ida agrees and signs both performA and performB tx bodies.
  • performA (Head A)

    • Finalizes transfer of assets from Alice to Ida in Head A.
  • performB (Head B)

    • Finalizes transfer of assets from Ida to Bob in Head B.

One-hop payment with ad-hoc ledgers

Continuing with the example use case of two Hydra heads A and B, with Alice in Head A and Bob in Head B, and Ida as the intermediary i.e. present in both heads, we will analyze a Lock operation of a one-hop payment with ad-hoc ledgers.

The Lock operation is the first step of the one-hop payment, akin to the HTLC Lock operation. It is the operation that locks the assets to be transferred from Alice to Bob via Ida.

Wrapping UTxOs

The first step for being “inside” of the corresponding replica of the ad-hoc ledger is to wrap the UTxOs that will be used to perform the atomic transaction (the Lock transaction in this case).

Each ledger (in this case, Head A and Head B) will contain a replica of the ad-hoc ledger Lₚ, named replica R₀ in Head A and replica R₁ in Head B. The replicas, as stated above, are defined by the set of wrapped UTxOs that are semantically equivalent between them.

Wrap UTxO

Verify the Lock transaction

The next step is to verify the Lock transaction. This is done by the verify step of the explained mechanism.

Verify Lock transaction

Perform the Lock transaction

The final step is to actually perform the Lock transaction. This is done by the perform step.

Perform Lock transaction

What’s the difference between using ad-hoc ledger or a simpler HTLC across L2s?

The main difference between using an ad-hoc ledger and a simpler HTLC is that the ad-hoc ledger allows for atomic transactions across multiple ledgers, while the simpler approach doesn’t.

Concretely, for the lock operation using just plain HTLC on two ledgers isn’t atomic. One of the parties could do the lock operation and then the other party don’t, and this would result in a liquidity trap until the HTLC expires. On the other hand, the ad-hoc ledger allows for more complex interactions via the verify→perform mechanism, where the verify step is reversible and the perform step is irreversible.

Also, the collateralization burden is distributed across the intermediaries, rather than being concentrated on one party. This makes the protocol more robust to failures and more flexible to different scenarios. By the paper, this makes the transfer between ledgers more capital efficient.

Further investigation about these (and more) differences will be done throughout the project.

Milestone 2

Consists of two parts:

  1. HTLC + Vesting implementation
  2. Ad-hoc ledgers verify-perform mechanism PoC

HTLC + Vesting implementation

For this second milestone, we extended the HTLC contract implemented in MS1. By adding output validation, we allow the HTLC to enforce the creation of smart contract UTxOs during the claim operation. We also implemented a very simple vesting contact to use as an example of inter-head smart contract interaction.

The canonical use case for HTLCs, explained in MS1, require two parties interested in executing a transaction (Alice and Bob in our case). This way, the party that will receive the funds is in charge of generating the preimage and sharing the hash, the other party creates the HTLC. This dynamic is important, if there’s only a single party interested in making the transaction, the flow breaks, so, in order to maintain it, the example we choose is a vesting contract, where Alice is sending funds to Bob, but they will be unlocked at a future time. Bob can share the preimage once the funds are guaranteed by the HTLC 2.0 contract to be sent to the vesting address with the appropiate timeout.

HTLC 2.0 Improvements

We’ll list the changes made from the HTLC desing in MS1, anything not mentioned in this document is the same as the previous version, which you can read more in the corresponding section of the ms1 document.

The first change was to add a new data type called DesiredOutput, this type represents everything we want to specify as the desired output when claiming the HTLC, including a non-opaque representation of a Value and an optional datum (if a datum is included, we force it to be Inline).

UTxO Specification

Datum

  • hash: ByteString
  • timeout: PosixTime
  • sender: VerificationKeyHash
  • receiver: VerificationKeyHash
  • desired_output: DesiredOutput

DesiredOutput

  • address: Address
  • value: Pairs<PolicyId, Pairs<AssetName, Int>>
  • datum: Option

HTLC Transactions

Claim funds

Consumes a HTLCUtxo with the Claim redeemer, providing the preimage of the stored hash. This transaction must be submited before the timeout, signed by the receiver and create the desired_output.

Claim funds from HTLC

Vesting Contract

The vesting contract is a single validator with a single operation, “Claim”.

UTxOs Specification

VestingUTxO

Address

  • Script address
  • Datum

  • vest_after: PosixTime

  • receiver: ByteArray

Value

  • min ADA
  • offered tokens

Vesting Transactions

Lock Funds

Creates a VestingUTxO containing the offered tokens. The datum specifies the “vest after” timeout in posix time from when the tokens become available to claim and the receiver that can claim them. This transaction has no validation, so the fields of the datum must be carefully considered. An invalid pubkeyhash or a timeout on the far future might make the UTxO unspendable.

Lock funds into vesting UTxO

Claim Vesting

Consumes a VestingUTxO. This transaction should be submitted after the deadline and signed by the receiver.

Claim funds from a vesting UTxO

Drawbacks of this design

As mentioned in the introduction, HTLCs still require two parties to be interested in the transaction taking place. For single party examples, like Alice wanting to place a bet in a lotery happening in another head, the preimage and hash management becomes fuzzy. This issue is demonstrated further when you take into account that Alice has no way to ensure that the HTLC UTxO that Ida created in Head B has the correct desired_output. For a single party example, this makes it a fully trusting protocol. For the dual party example, this is still not ideal. Bob could collude with Ida to make the timeout of the vesting UTxO shorter, or delete it altogether. A potential solution would involve making the desired_output field part of the hash, so the claim becomes impossible if this value is tampered with.

This solution sounds ideal, but the issue now becomes that the desired_output is not the same in Head A a in Head B. In Head B we want to create the vesting UTxO in the name of Bob for a future timeout, but in Head A, Ida would want to recover the assets as soon as possible without waiting and certainly without having to get Bob’s signature.

This design constraints will be discussed in more detail once we start to compare HTLCs with the Ad-hoc ledger approach.

Ah-hoc ledger verify-perform mechanism PoC

The main goal is to atomically execute a transaction original_transaction across two ledgers L₀ and L₁, resulting in spending UTxOs in L₀ and producing outputs in L₁ as if they were in the same logical ledger Lₚ, the ad-hoc ledger.

The requirements for the mechanism are:

  • intermediaries need to verify that original_transaction can be executed, before the actual effects are performed on both ledgers
  • intermediaries shall be able to check wheter original_transaction could be applied on source ledger and target ledger (via collateralization).
  • the end result of the mechanism is either that the original_transactions is fully applied on both ledgers, or in none of them.

We’ll start with implementation ideas, with explanation of their respective limitations, challenges and future improvements.

Contract Design - Version 1

The mechanism is comprised of the following operations:

  • verify: verify a future perform transaction in this ledger.
  • perform: perform the already-verified transaction.

Wrapped UTxOs

L2 users will send UTxOs to the Lp script address for making them available in the ad-hoc ledger.

  • Address: Lₚ script
  • Value: any
  • Datum:
    • owner: Address
    • intermediaries: List[PublicKey]

Reserved UTxO

The state UTxO used to store the reserved wrapped UTxOs. Its NFT will be minted by the mint purpose of the Lp script.

  • Address: Lₚ script
  • Value: 1 NFT
  • Datum:
    • reserved_utxos: Map[TransactionHash, List[OutputRef]]

Lₚ script

  • Spend purpose redeemers:

    • Verify
    • Perform
  • Mint purpose redeemers:

    • Data: for minting the Reserved UTxOs
  • No other purposes allowed

Operations overview

The verify operation will mark some specific UTxOs as reserved for a perform transaction, while disallowing the usage for other verify operations. The marked UTxOs list will be stored in the datum of a unique “state UTxO” for the ad-hoc ledger. By off-chain mechanisms, the UTxOs will be tagged with the perform transaction hash, and a set of privileged participants will cosign the transaction as a way to guarantee some level of security.

Verify

The perform operation will consume their reserved wrapped UTxOs, and validate its hash against the tag of those UTxOs.

Perform

As stated in the verify-perform mechanism description for ms1 deliverable, each L2s replica of the ad-hoc ledger must be semantically equivallent i.e. same UTxO set except their addresses, for ensuring no liquidity traps. This consistency, along with the correct ordering of the operations for atomicity, is ensured by the intermediaries cosigning the verify and perform transactions in each L2 replica.

Restrictions, Notes & Future Improvements

  • Any piece of data that is needed for the perform operation could not be related to the verify operation in any way, since we need to calculate the perform tx hash before building the verify transaction.

This happens because if we relate a verify-perform pair by the perform transaction hash, we need to build the perform transaction before building the verify tx. This implies that the reserved UTxOs could not be spent in both transactions, nor the reserved UTxO datum could be updated in both transactions.

Even more, reserved UTxO datum could not be updated in the verify transaction only because it must be referenced in the perform transaction with the verify tx hash, which is unknown at the time of building the perform transaction body.

So, the core problem to solve is how to on-chain relate verify and perform transactions in order to ensure atomicity and consistency, taking into account the previous constraints.

  • The intermediaries might be a parameter of the Lₚ validator instead of being part of the reserved UTxOs datum?

  • How to relate on-chain Lₚ scripts from different heads? We might need a unique identifier mechanism, as proposed in the paper.

  • How to prevent intermediaries from cheating by doing verify-perform in only one head, whilst doing nothing in the other head? This might be a concern for the dispute mechanism proposed in the paper, and subject to further research in a coming milestone.

Contract Design - Version 2

We need a more flexible version in terms of the constraints regarding the relationship between the verify and perform transactions. So, we’ll do a very simple version that we’re sure that works, and add constraints in later versions for iteratively adding security and decentralization guarantees.

In this version, the verify will consume the UTxOs meant to be inputs to the perform transaction, add them a specific “validity token” that could be recognized by the perform transaction. Then, perform will consume the UTxOs and burn those tokens.

This way, we offload to the intermediaries the responsability of doing the proper inspection and execution of both the verify and perform transactions. Later version must favour on-chain code over intermediaries supervision.

Wrapped UTxOs

Same as Version 1.

Lₚ script

  • Spend purpose redeemers:

    • Verify
    • Perform
  • Mint purpose redeemers:

    • MintVerified: for minting validity tokens. This tokens “reserve” the UTxOs for a future perform transaction.
    • BurnVerified: for burning validity tokens.
  • No other purposes allowed

Operations overview

The verify operation will consume the UTxOs meant to be inputs to the perform transaction, add them a specific “validity token” that could be recognized by the perform transaction. Then, perform will consume the UTxOs and burn those tokens.

Let’s consider the example of applying the mechanism for wrapping a UTxO.

Verify

verify consumes the User UTxO and adds a validity token to it, meaning is reserved for the perform transaction.

Perform

Then, perform consumes the User Wrapped UTxO and burns the validity token, meaning the UTxO is available within the Lₚ script for other operations. These other operations must also use this mechanism to ensure atomicity.

Notes & Future Improvements

  • There’s no constraint that explicitly relates a pair of verify and perform transactions. A non-scalable approach might be to restrict the mechanism to only one verify happening at a time, with each verify having a very short timeout for the perform transaction to be executed. Resolving this on-chain is quite neccessary for being a robust mechanism.

  • Also, the constraint of actually doing the perform that the intermediaries and owners agreed about in verify is not enforced by this implementation. This is delegated to the good faith of intermediaries. We must tighten this solution to match the requirement in a future enhancement as well.

  • Add unique identifier mechanism to relate the “same” Lₚ script from different heads.

  • Add collateral slashing tracking between intermediaries, for answering: how much of the value of each collateral UTxO is from each intermediary?

Contract Design - Version 3

A middle-ground between Version 1 and Version 2.

For solving the problem posed by Version 1 of circularity happening by relating a verify-perform pair with the perform transaction hash, we must break it. This can be achieved by

  • labeling the reserved inputs with a token, or with some other mechanism as in Version 2. This avoids verify double-spending as well. Another option is to trust the intermediaries on not verifying more transactions than the ones they’re cappable of performing with the available inputs.
  • create a spec for the expected perform transaction outputs: spec for the original transaction outputs.

The outputs spec definition and usage is challenging, but we can think of using the transaction redeemers to pass that information.

  • pass by redeemer the expected perform outputs spec to verify. verify collects inputs, validates that is possible to produce the perform outputs from them, and reserves those inputs by attaching a token (as in Version 2).
  • perform just collects those reserved inputs, burn their marker tokens (in case of using tokens) and produces the outputs.

Then, there’s still an issue to resolve: how do we ensure that perform actually consumes the verify-marked inputs and produces the expected outputs?

A possible solution might be to produce a hash from the outputs spec, and use it as the token name of the verify-minted tokens, which in turn are attached to the marked inputs. Then, in perform we burn those tokens and validate that hashing the produced outputs matches the name of the tokens being burnt. This way, we relate a pair of verify-perform while avoiding clashes between distinct verify’s.

Milestone 3

Consists of two parts

  1. Multi-L2 topologies
  2. Model efficiency comparisson and performance

In this third milestone we are looking at how we can extend the system we’ve built to more than two L2 ledgers. We look into multiple possible topologies and compare how different configurations of topologies and models perform.

Topologies Explanation

Two-heads topology

Two Heads topology

The two-heads topology is the simplest one, it consists of two heads, each with two participants.

The use case for this topology is HTLC-based payments between two parties from different heads, with some party acting as intermediary (present in both heads) i.e. single hop payment.

Single-path topology

The single-path topology is the natural expansion of the two-heads topology, for each new participant a new head is added with a new intermediary that “joins”1 the previous end head as well. In this manner, each user can interact directly with at most two other users. Each “middle” head now has three participants, one user and two intermediaries while both ends of the chain have only two participants. Using this topology payments might require up to M-1 hops for M heads, with the benefit of splitting the liquidity requirements between multiple intermediaries.

The single path topology for three and four heads would look like this:

Single Path three heads

Single Path four heads

And it’s easy to see that it can be expanded indefinitely.

While this expansion seems natural, it comes with some pretty big drawbacks. Mainly, each new user increases both median and max path lenghts, and at some point the cost and latency would become so big that it would be better to do payments through the L1 instead. Also, having users in a hydra head along a payment path, would require those users to be online and to sign the corresponding snapshots even if they are not part of the deal. Let’s see how we can improve on those two points.

1

As we are talking about static topologies, participants don’t join already running networks. Rather they join during a “planning” phase where heads and intermediaries are being designed.

Hub-and-spoke topology

Realizing that we need to isolate each user on it’s own path, we can experiment with another common topology, the hub-and-spoke topology. In this topology, a single intermediary acts as hub for all users. Creating only pair wise heads, and allowing any payments to be achieved with a single hop. For each new participant a new head is added with the intermediary in it.

Hub and spoke with three or X heads, here we represent Ida outside the heads to show that all payments flow trough them in a single hop

Hub and Spoke three heads

Hub and Spoke X heads

As mentioned before, all payments in this topology are single hop payments, and we can see that is the case no matter how many users we add. The main drawback of this design now becomes liquidity, we need a single intermediary to achieve this level of transaction efficiency, but this carries a high liquidity requirement for the intermediary.

Model efficiency

Now that we presented some common topologies, we will compare the theoretical efficiency of the adhoc-ledger design vs point-to-point transactions and the implemented HTLC system across multiple dimesions such as:

  • Transaction cost/count
  • Liquidity constraints

Transaction cost

Transaction costs can be divided up into two categories:

  • L1 setup costs
  • L2 transction costs

L1 Costs

The costs in L1 are pretty much constant for all topologies and systems used. For each head we need a set of transactions, namely an Open Head transaction, one Commit transaction per participant in the head and one CollectCom transaction. For closing the head, a Close and a Fanout transaction are needed. Fees for each transaction are:

Now, for each two party head we have a total of:

For a three party head, all costs are the same, but another Commit transction is needed, so costs per head grow to 14.38 ADAs. In total, a SinglePath network as described needs two 2-party heads and 3-party heads when where is the number of heads. For a hub-and-spoke network, 2-party heads are needed, making it a much cheaper alternative overall.

We got these costs by opening a two party head in preprod with the latest hydra node (1.2.0), these are the tx hashes:

L2 Costs

L2 Transaction cost is hard to pinpoint due to the configurable nature of L2s. In hydra for example, each head can set their own parameters and it is often the case where transaction fees are waived completely. Nonetheless we can compare the transaction count of different scenarios to get an idea of which is more efficient.

HTLC

Using HTLCs, for a single hop flow we have a total of four transactions, two create and two claim. Each additional hop adds a new create and claim transaction. Create transactions don’t run any plutus script while claim transactions have some basic validations. We can then express the fee cost for hops as follows:

Where is the base cost of a transaction and is the added cost of running the HTLC script in lovelaces.

It’s clear that a multi-hop setup like the single path topology would require more fees than the single hop hub-and-spoke topology.

Adhoc ledger

The adhoc ledger system once it’s up and running needs a verify and a perform transaction, both done in all heads where the ledger is setup and both needing to run plutus validation, so for a given topology the cost is constant,regardless of the sender and the recipient. We can express the costs as follows:

Now, given that for heads we have at most hops for an htlc, the worst case scenario for a single payment becomes , which is less than or equal to the adhoc , given that and .

Where the adhoc ledger becomes poweful is in it’s ability to perform multiple payments in the same transaction. If Alice wants to pay both Bob and Charlie, she would need two HTLCs, but a single transaction in the adhoc model. To give the HTLC it’s best fighting chance we will assume we will be analysing this case with the hub-and-spoke topology, meaning that all payments require a single hop. Then, to make payments with HTLCs, we have a cost of

Comparing with the Adhoc model is not straightforward, since the HTLC cost depends only on the number of payments and is independent of the number of heads, whereas the Adhoc cost is independent of the number of payments and depends only on the number of heads. We can do some analysis for when the HTLC becomes more expensive than the adhoc:

From looking at htlc transactions, we can say that a broad estimate for and in a preprod like enviroment is and respectively, given that there’s only one pltus script running at a time and the validations are rather simple2. Using those numbers we have that HTLCs become more expensive when meaning that if a user want to pay more than half of the total number of users, it is cheaper to use an adhoc ledger system, purely from a transaction cost analysis.

2

Adhoc validations would have a higher cost, however even if plutus validation becomes 10x higher, the results don’t change in a significant way.

Liquidity contraints

Let’s asume a desired capacity of , that means that we want to be able to send from any user to any other, up to lovelaces. And let’s compare how much liquidity is required from the intermediaries in different topologies and systems.

Single Path

For the single path topology, each intermediary in each head must have of liquidity. That means the for each middle head we need of liquidity, and just for the end heads. (We are not counting user liquidity, just intermediary liquidity). In total we have liquidity required, with each intermediary needing exactly .

Hub-and-spoke

For the hub-and-spoke topology, the requirements get cut by a significant amount, by only having one intermediary per head, the total requirement is now . But the downside is that this liquidity must be provided by a single intermediary.

Adhoc ledger

Lastly, for the adhoc ledger, if we assume that we create ethereal ledgers, that is wrapping the utxos just before using them and unwrapping just after creating the new ones, the total requirement is also , but if the utxos stay wrapped, the total liquidity requirement by wrapping lovelaces from each user in all heads, can be as high as . The big benefit of the adhoc ledger design is that it allows the liquidity to be provided by multiple intermediaries in any proportion they see fit.

Recomendations

For a big scale deployment we think it’s best, as it’s usually the case in life, a balanced approach that would consist of multiple hub-and-spoke clusters, with the hubs themselves creating a single path network. This topology would minimize hops needed between close participants while aliviating liquidity pressure from intermediaries, allowing them to add more spokes as more liquidity is aquired.

Milestone 4

Consists of three parts:

  1. Adversarial Scenarios
  2. Ad-hoc ledger V4 specification
  3. Test suite

This milestone focuses on adversarial scenarios and implements the dispute mechanism to ensure that funds cannot get stuck indefinitely.

Adversarial Scenarios

Adversarial scenarios occur when parties involved in a cross-ledger operation fail to cooperate. These situations are secured by two primary mechanisms: the on-chain smart contracts ensure that funds cannot be stolen or permanently locked, while the Hydra Head protocol ensures that progress is possible even if some participants become unresponsive.

An important aspect of these L2-to-L1 transitions is the Hydra contestation period. Before any disputed state can be settled on L1, the head must be closed and fanned out. This requires waiting for a contestation window, which in production environments may last for several days. Only after this period has elapsed can the final L1 transactions be submitted to resolve the dispute.

In this milestone, we consider two primary adversarial scenarios:

Dispute in L2 and merge on L1

In this scenario, a party (e.g., an intermediary) ceases cooperation with the adhoc-ledger protocol (but continues to participate in the Hydra Head) after funds have already been wrapped. The dispute is initiated within the L2 Hydra Head, but final resolution occurs on L1 after the head is closed.

  1. Setup: Alice wraps X ADA in Head A. Intermediaries Ida and Jhon wrap their collateral in Head B. Both UTxOs share the same nonce.
  2. Stall: Jhon stops responding (e.g., refusing to sign a Verify transaction).
  3. Dispute (L2): Alice invokes the Dispute redeemer on her Wrapped UTxO within Head A. This marks the UTxO as disputed and starts an internal timeout.
  4. Dispute (L2): Ida calls Dispute on the Collateral UTxO in Head B to protect her funds from being locked by Jhon’s inaction.
  5. Fanout: The Hydra heads are closed. After the contestation period expires, the disputed UTxOs are fanned out to the L1 ledger.
  6. Merge (L1): On L1, the fanned-out disputed UTxOs are spent together in a single Merge transaction.
    • Alice recovers her original X ADA.
    • Ida and Jhon recover their respective collateral.
sequenceDiagram
    participant AliceL2 as L2 (Head A)
    participant CollatL2 as L2 (Head B)
    participant L1 as L1 Ledger

    AliceL2->>AliceL2: Wrap Funds (X ADA)
    CollatL2->>CollatL2: Wrap Collateral (Ida & Jhon)

    Note over AliceL2, CollatL2: Jhon Stalls

    AliceL2->>AliceL2: Dispute Wrapped UTxO
    CollatL2->>CollatL2: Ida Disputes Collateral UTxO

    AliceL2->>L1: Fanout (Disputed UTxO)
    CollatL2->>L1: Fanout (Disputed UTxO)

    L1->>L1: Merge Disputed UTxOs
    Note right of L1: Alice gets X ADA<br>Ida & Jhon get collateral

Dispute and merge on L1

In this scenario, an intermediary stops signing Hydra snapshots entirely, effectively freezing the L2 head and preventing even L2 transactions like Dispute. The participants must force-close the heads, moving the dispute logic to L1.

  1. Setup: Alice wraps X ADA in Head A. Intermediaries Ida and Jhon wrap their collateral in Head B.
  2. Stall: Jhon refuses to sign new snapshots. Head B can no longer progress.
  3. Fanout: Participants close the heads (i.e., Ida closes Head B to avoid losing collateral). Once the contestation period ends, the Wrapped UTxOs fan out to L.
  4. Dispute (L1): On L1, Alice calls Dispute on her fanned-out Wrapped UTxO.
  5. Dispute (L1): Similarly, Ida calls Dispute on the Collateral UTxO on L1.
  6. Merge (L1): Once both replicas are marked as disputed on L1, they are merged in a single transaction, refunding all parties.
sequenceDiagram
    participant AliceL2 as L2 (Head A)
    participant CollatL2 as L2 (Head B)
    participant L1 as L1 Ledger

    AliceL2->>AliceL2: Wrap Funds (X ADA)
    CollatL2->>CollatL2: Wrap Collateral (Ida & Jhon)

    Note over AliceL2, CollatL2: Jhon stops signing snapshots

    AliceL2->>L1: Force Close (Fanout Wrapped UTxO)
    CollatL2->>L1: Ida Force Closes (Fanout Collateral UTxO)

    L1->>L1: Dispute Alice's UTxO
    L1->>L1: Dispute Collateral UTxO

    L1->>L1: Merge Disputed UTxOs
    Note right of L1: Alice gets X ADA<br>Ida & Jhon get collateral

Complete intermediary unresponsiveness (Punish)

In this scenario, all intermediaries cease cooperation entirely and refuse to participate in any further actions. Alice must use the Punish mechanism to reclaim her funds and subsequently seize the intermediaries’ collateral.

  1. Setup: Alice wraps X ADA in Head A. Intermediaries Ida and Jhon wrap their collateral in Head B.
  2. Stall: Ida and Jhon stop responding entirely. Head B can’t progress.
  3. Fanout (Head A): Alice closes Head A.
  4. Dispute & Punish (L1): Alice calls Dispute on her fanned-out Wrapped UTxO on L1, starting the timeout. Once the timeout expires without a merge resolution, she uses the Punish redeemer to claim her original X ADA back.
  5. Fanout & Punish (Head B): Head B remains frozen. When Head B is eventually closed by another user, the Collateral UTxO is fanned out to L1, Alice can call Dispute and subsequently Punish on that UTxO to claim both Ida’s and Jhon’s collateral. Note that merge is no longer an option because the original disputed UTxO has been consumed already.
sequenceDiagram
    participant AliceL2 as L2 (Head A)
    participant CollatL2 as L2 (Head B)
    participant L1 as L1 Ledger

    AliceL2->>AliceL2: Wrap Funds (X ADA)
    CollatL2->>CollatL2: Wrap Collateral (Ida & Jhon)

    Note over AliceL2, CollatL2: Intermediaries stop responding entirely

    AliceL2->>L1: Force Close (Fanout Wrapped UTxO)

    L1->>L1: Dispute Alice's UTxO
    Note right of L1: Timeout expires

    L1->>L1: Alice uses Punish redeemer
    Note right of L1: Alice recovers X ADA

    Note over CollatL2: At a future date...
    CollatL2->>L1: Head B force-closed (Fanout Collateral UTxO)

    L1->>L1: Dispute Collateral UTxO
    Note right of L1: Timeout expires

    L1->>L1: Alice uses Punish redeemer
    Note right of L1: Alice claims Ida & Jhon's collateral

Funds Ownership guarantees

It’s important to note that in all scenarios, once Alice initiates the dispute process, she is guaranteed to recover her funds by waiting for the timeout and using the Punish redeemer, even if intermediaries become unresponsive.

Intermediaries have a strong incentive to complete the protocol flow (i.e., the Merge transaction on L1) before the timeout to recover their collateral. If no honest intermediaries remain, those funds will be lost and eventually paid to Alice for the troubles. Head B will eventually be closed because we assume there is at least one honest user participating there that is not an intermediary, otherwise, there would be no reason for Alice to bridge funds to that Head in the first place.

Midgard <> Hydra Scenarios

Scenarios involving Midgard follow a similar logic but benefit from different liveness guarantees. Unlike a Hydra Head, which can be stalled if a single participant stops signing, Midgard works by having multiple operators that take turns in a round-robin system validating transactions and modifying the ledger.

If a specific operator refuses to validate transactions, the user simply waits for the next operator’s shift to resubmit the transaction. This inherent robustness applies to both the Dispute transaction on L2 and the Withdraw event used to bridge UTxOs back to L1.

However, Midgard also imposes a delay: the confirmation period. Similar to Hydra’s contestation period, Midgard requires a waiting period (which can last up to a week according to the specification) before an event is considered final and can be used on L1. Once this period passes, the rest of the L1 resolution flow (Dispute and Merge) remains identical to the Hydra scenarios described above.

Contract Design - Version 4

warning

This implementation is a proof of concept and should not be considered safe to use in it’s current state

This new version of the contract modifies the verify-perform mechanism again, removing the token minting and consolidating reserved inputs into a single UTxO. To allow this operation to be reversed, the original inputs are stored in the inputs field of the VerifiedDatum. The outputs that need to be generated after the perform step are stored in the outputs field of the same datum.

Version 4 also introduces a dispute mechanism to prevent cross-ledger operations from getting stuck indefinitely. This is achieved by adding new redeemers (Dispute, Merge, Punish) and new datum fields (disputed, timeout, nonce) to the wrapped UTxO validator.

This way, if an intermediary stalls the protocol, any participant can dispute the wrapped UTxO. Once disputed in both replicas, the UTxOs can be merged on L1 (after head fanout) to recover the funds. If the counterparty does not cooperate with the merge, the disputer can punish them after the timeout, claiming all value including collateral.

Wrapped UTxOs

L2 users send UTxOs to the Wrapped script address to make them available in the ad-hoc ledger.

  • Address: Wrapped script
  • Value: any
  • Datum:
    • owner: VerificationKeyHash
    • intermediaries: Pairs<VerificationKeyHash, Int> (maps intermediary → their collateral share in lovelace)
    • nonce: OutputReference
    • disputed: Bool
    • timeout: Option<Int>

Wrapped script

  • Spend purpose redeemers:
    • Unwrap
    • Verify
    • Dispute
    • Merge
    • Punish

Verified UTxOs

The verified validator stores the state of a verified transaction, including the inputs (for reverting) and outputs (for performing).

  • Address: Verified script
  • Value: the locked value
  • Datum:
    • inputs: List<DesiredOutput> (for reverting to previous state)
    • outputs: List<DesiredOutput> (for performing the intended state change)

Verified script

  • Spend purpose redeemers:
    • Revert
    • Perform

Operations overview

Wrap

Sends a user UTxO to the Wrapped script address. No on-chain validation is run during wrapping; the user simply pays to the script with an inline datum.

Wrap UTxO

Unwrap

Consumes a Wrapped UTxO and sends the value back to the owner. Must be signed by the owner.

Unwrap UTxO

Dispute

Consumes a Wrapped UTxO with the Dispute redeemer. This marks the UTxO as disputed and sets a timeout. Either the owner or an intermediary can initiate the dispute.

The validator enforces:

  • Signer is owner or an intermediary
  • Datum fields owner, intermediaries, and nonce are preserved
  • disputed is set to True
  • timeout is set to Some(T)
  • Value and address are preserved

Dispute UTxO

Merge

Consumes both disputed replicas (same nonce) in a single transaction on L1 after the heads have been fanned out. This resolves the dispute by unwrapping the value to the owner and distributing collateral to intermediaries.

The validator enforces:

  • The UTxO being spent is disputed (disputed == True)
  • A replica input exists with the same nonce and same script address, and it is also disputed
  • The first output sends the value to the owner’s address
  • Subsequent outputs distribute to intermediaries according to the intermediaries pairs

Merge dispute

Punish

If the dispute timeout expires without a merge resolution, the owner can claim all value from the disputed UTxOs, including the intermediaries’ collateral. This disincentivizes intermediaries from stalling indefinitely.

The validator enforces:

  • The timeout has expired
  • Signed by the owner

Punish timeout

Verify

Consumes a Wrapped UTxO with the Verify redeemer and pays to the Verified contract. The verified datum stores both the original inputs and the intended outputs.

Verify UTxO

Revert

Consumes a Verified UTxO with the Revert redeemer and restores the original Wrapped UTxOs.

Revert

Perform

Consumes a Verified UTxO with the Perform redeemer and produces the intended outputs as new Wrapped UTxOs. Must be signed by all intermediaries

Perform

Test suite

This milestone includes a test suite designed to validate a simpler version with only one intermediary of the adversarial scenarios through two distinct approaches:

  1. Emulator-based Tests: These tests utilize an emulator to verify the on-chain contract logic in isolation. They abstract away the actual L2 implementations and replace the L2 mechanism of bridging funds from L1 to L2 and back with a test driver that maps UTxOs between the emulator instances. This proves that the protocol is generic and can work for any L2 that meets the abstracted interface. Because of this, and given other advantages like faster execution and lower computational overhead, they are integrated into our GitHub Actions workflow.

  2. End-to-End Local Node Tests: These tests run against a full local Cardano node and using real Hydra Heads. They validate the entire system’s behavior, including the lifecycle of Hydra Heads (opening, committing funds, disputing UTxOs, and closing).

Logbook that contains thinking, discussions, pains, joys, events, and experiences that happen while working on this project. It is supposed to be a kind of Stream of consciousness that can later be searched, linked to or reviewed. It may also be used as a very informal decision log.

2025-04-04

By @ch1bo and @SwiftlyUnmoving

  • Discussing our take-aways from the paper
  • Glances over the fact that script spending does not generalize easily
  • Collateralization and fee structure is handwavy and could be problematic
  • How to make NFTs minting policy compatible with L2s
    • Case on script context and have values for Hydra, Hydrozoa, Midgard, …?
    • Equivalent of a spending validator agreeing to be committed into L2
    • But we would need to delegate trust to Hydra, Midgard etc. when minting happens later on L1
    • On L1 we can identify that we are minting in e.g. a Hydra fanout and can green-light this if the validator set is enough
  • Interfacing spending validators with L2s (on committing) is equivalent to using them for atomic transactions across L2
  • Atomic transactions across L2s is kind of equal to establishing an L3 (and that same interfacing problem when going L2 -> L3)
  • Spending and minting needs to be compatible with the cross ledger protocol (i.e. the wrap-perform transaction)
  • Collaterizing NFTs is an issue for any cross-ledger protocol!
    • While in the L2 case, there may be a chance to avoid duplication as we share the same L1 and a dispute protocol can exist
    • However that would still mean that one party will only be refundend the collateral instead of the NFT
    • Also: What’s sufficient collateral for one NFT, who decides?
    • Too high collateral limits liquidity / reach of such an NFT (each intermediary set would need to be liquid enough)
    • Even harder to estimate for state thread tokens (which ensure contract continuity)
      • Consolidation of smart contract state is going to be hard.
  • How does the ad-hoc ledger concept scale?
    • For example in doing multiple hops and routing
    • In principle, collateral should be sharable across inermediaries (per hop)
    • We should model this to see wheather the whole feasible the concept is
    • Timing within payment channel networks is adding up, is this the case here too?
  • Difficulty levels of “asset under interop”
    • Easiest: one currency value (UTxO = Bitcoin)
    • Easy: multiple, fungible assets (UTxO-ma, only FT)
    • Medium: non-fungible tokens (UTxO-ma, also NFTs)
    • Hardest: fully scriptable spending and minting (EUTxO)
  • Liquidity across the path
    • Lightning already has the complexity of direction in liquidity
    • In a full UTxO ledger, it is even more difficult as the assets might not be owned by the validator
    • Need to know how much collateral is available for route finding
  • Do we even benefit from UTxO ledger model over an account model?
    • Maybe not?
    • Would simplify collateral allocation
    • Indidividual state channel interactions might benefit from it, but for bridging / routing funds across ledgers not so much?
    • One account for each interop protocol intermediary (= collateral available = liquidity available)
  • What if liveness of L2 breaks down?
    • Wrapped UTxOs must be recoverable or performable on L1
    • We should “front load” as much work as possible in the wrapping (aka verify) transaction so that perform or dispute can always fit on L1 even
  • We also mentioned in passing that the only way we could do full script verification (with simulated script context) for verify would be by side-stepping the L2 ledger and build support into Hydra/Midgard
  • Also: is there a timeout before a dispute can be made? Otherwise we would race between signing perform and doing a dispute -> or is this not an issue?

2025-04-01

By @ch1bo

  • Want to establish a logbook to put notes for this project
  • Rendering into the mdbook like I started doing for cardano-blueprint seems useful too
  • Hower, using the Github wiki as a logbook is producing less noisy commits on the main repository
  • The github wiki is also a repository we can add as a submodule, i.e.
    git submodule add wiki git@github.com:cardano-scaling/eutxo-l2-interop.wiki.git
    
  • Then, symlinking the the logbook.md into book/ and adding it to SUMMARY.md does the trick
  • Now, only nix is choking on submodules (as always)
  • Found the idea of tracking the submodule as a flake input online in this thread https://discourse.nixos.org/t/get-nix-flake-to-include-git-submodule/30324/16
  • Now, we track the submodule commit also in the flake.lock, but at least the nix build works as-is.

2025-03-25

By @ch1bo

  • Re-read the research paper and started a summary in the technical report
  • Approach is quite “ad-hoc” indeed and borrows on generalization of HTLCs being similar “two-step commit schemes”
  • Relevant other paper SoK: Communication Across Distributed Ledgers which focuses on cross chain communication, but establishes as generic model: “A generic CCC protocol consists of three main phases: commit (on X), verify (and commit on Y ), and an optional abort”
  • Could improve some terminology around “utxo addresses” which seem to be rather “output references”
  • Wrap + perform is basically a two stage commit similar to the above
  • Script continuity of verify-perform? What if L2 closes? Need intermediaries ensure continuity somehow “on top” of running the L2 ledger?
  • UTxO and UTxOma should be “embeddable” into EUTxO protocol for ad-hoc ledgers - as they do not require general scriptability
  • Verifying the transaction on “wrap” sounds like side-stepping the EUTxO ledger? i.e. simulate a script context with outputs as they would on perform
  • Mint tokens on wrapping -> why not on perform? to avoid burning in case of dispute
  • Setting a dispute flag on the wrapped UTxO would rather be another state of the protocol!?
  • What if liveness of L2s break?
  • The biggest open questions remain:
    • How to collateralize NFTs?
    • How to generically wrap script UTxOs without side-stepping EUTxO ledger?
    • How to ensure script continuity of wrap + perform steps (without minting tokens ourselves; what if L2 closes)?

Demo

Diagrams & Maths

We can use mermaid diagrams (live editor):

graph LR;
    A-->B-->D;
    A-->C;

and maths using katex:

Alerts

warning

We can use the github flavored callouts, documented here

note

A friendly note in github. How about code blocks?

cargo install mdbook-alerts

Footnotes

Additional information that would complicate the read-flow can be put into footnotes 1.

1

Example footnote