Skip to content

CIP-0118? | Nested Transactions #862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 47 commits into
base: master
Choose a base branch
from

Conversation

polinavino
Copy link

@polinavino polinavino commented Jul 23, 2024

We propose a set of changes that revolve around validation zones, a construct for allowing certain kinds of underspecified transactions. In particular, for the Babel-fees usecase we discuss here, we allow transactions that specify part of a swap request. A validation zone is a list of transactions such that earlier transactions in the list may be underspecified, while later transactions must complete all partial specifications. In the Babel-fees usecase, the completion of a specification is the fulfillment of a swap request. We discuss how validation zones for the Babel fees usecase can be generalized to a template for addressing a number of use cases from CPS-15.


📄 Rendered Proposal

@polinavino polinavino changed the title Validation Zones CIP-0118 | Validation Zones Jul 23, 2024
@rphair rphair changed the title CIP-0118 | Validation Zones CIP-0118? | Validation Zones Jul 23, 2024
@rphair
Copy link
Collaborator

rphair commented Jul 23, 2024

thanks @polinavino ... really happy to see the continuation of this work. I'm marking the title with the obligatory ? because until merged the number (or its assignment at all) cannot be certain. Also I'm marking the prior version Likely Deprecated and will close as such with your confirmation:

cc (for continuing review from the old proposal) @Quantumplation @fallen-icarus - p.s. cc (re: Rationale ["towards better design"]) @AndrewWestberg

Copy link
Collaborator

@rphair rphair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it is proper for this to be a separate PR from the first one, though that should be confirmed by other CIP editors today (https://hackmd.io/@cip-editors/93 - cc @Ryun1 @Crypto2099). Given the significance of the revision, the commit history in this case I think is more important than the discussion history & hopefully any prior discussion points will be summarised by previous reviewers here (@fallen-icarus @Quantumplation).


## Path to Active

### Software Readiness Level
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with other CIPs (mainly for review in parallel with 100+ others) this section needs to be broken into Acceptance and Implementation ... I guess since it refers to testing functionality then it would be on the Implementation path.

When done sifting material around in this section it will also help for these items to be GitHub formatted tickboxes (- [ ]) but I am not going to be pedantic about it especially at this stage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, will do that later today!

@rphair rphair added the Category: Ledger Proposals belonging to the 'Ledger' category. label Jul 23, 2024
@WhatisRT
Copy link
Contributor

I think it's important to not restrict thinking to the Babel Fees application. @Quantumplation explained it quite nicely, but I'll say it a bit differently: the key feature here is that we want to turn interactive protocols (which require back & forth communication, which in practice would be with a centralized service) into non-interactive ones. In fact, we should be able to prove formally that for any transaction that contains subtransactions you can make a transaction without subtransactions that does the same thing (except that it has a different txid & fees).

For many applications, there might be ways to get non-interactive protocols in a different manner that doesn't require this feature. What nested transactions give you is a nice & easy way to get it in general. A more apt comparison with past features might be this:

Plutus is actually completely unnecessary if you want to implement an order-book DEX. You can just write a piece of software that allows you to announce swaps and intent to fulfull them e.g. by publishing metadata that contains partially signed transactions. It's completely decentralized and trustless and could have been done all the way back in Shelley even (though there weren't any interesting swaps you could do). I'm sure many other things that typically use Plutus could have similarly been implemented before Alonzo by finding some clever solutions.

All of that isn't to say that I think nested transactions is required or even a good feature. I haven't personally seen any use case that benefits from nested transactions sufficiently to convince me it's worth the effort (though I'd like to find out). As you've observed correctly, if you just want to do swaps where the participants don't pay the fees in ada you can have that today. I have one decent use case that might be relevant if we implement a particular Leios flavour, but it's not a terribly big thing and there are probably better ways to get that if that's the only use case.

@michele-nuzzi
Copy link

the key feature here is that we want to turn interactive protocols (which require back & forth communication, which in practice would be with a centralized service) into non-interactive ones

@WhatisRT the non-interactive part is not to attribute to nested transactions; The non-interactive part can be attributed to CIP-0137 or, more in general, to a data availability solution.

Once something like CIP-137 is available, anything that nested transactions aims to do, can be done with a simple signed redeemer as in the babel fee example, without unnecessarily modifying the ledger, and with more control by the user.

@lehins
Copy link
Contributor

lehins commented Jun 30, 2025

@michele-nuzzi So, back to my example of: "How can I today create a transaction without owning any ADA?"

You say that a smart contract approach allows one to implement a solution for this.

My question for you, how do I construct a transaction without owning any ADA? Even if your Babel Fee smart contract unlocks an input with ADA in it to pay for the fees, someone has to specify the collateral, which can't be locked by any script.

The provider only pre-signs (part of) the redeemer to be used in any transaction

So, no matter on what sort of clever smart contract solution one will come up with, it will be impossible for the end user to submit a signed transaction without that user owning any ADA. It would have to be the provider who'd be creating the final transaction if such use case is to be possible.

@michele-nuzzi
Copy link

michele-nuzzi commented Jun 30, 2025

@lehins we have to be realistic. What is the problem we are trying to solve?

There is no user with "no ada" due to minUtxo.

The problem we are trying to solve is not "allow someone without ada to transact" because such a user doesn't exist, the problem we are trying to solve is "pay a fee with any token".

Additionally, this problem only exists for simple transfers, where min collateral is less than minUtxo with no tokens for such a simple contract.

With collateral_percent set at 150, a tx that would take 0.2 ADA of fee only requires 0.3 ADA of collateral.

do you want to tell me the user does not have at least 2 utxos to do a transaction?

do we want to introduce also transactions for the "users that don't have utxos"?

@WhatisRT
Copy link
Contributor

There's a specific design question about whether simple scripts should be allowed in transactions containing subtransactions. Since following this PR is getting quite complicated I thought I'd try something new to spin out the conversation, which is to make a separate issue on the ledger specification repo. If you have any feedback or opinions on this topic, please leave a comment there!

IntersectMBO/formal-ledger-specifications#808

@fallen-icarus
Copy link
Contributor

fallen-icarus commented Jun 30, 2025

Regarding the ledger implementation version vs the smart contract version, I have some questions:

  1. What percentage of Cardano wallets are pubkey wallets? Nested transactions also works for pubkey wallets while the smart contract approach (by definition) does not. If 80% of all Cardano wallets use pubkeys, then the smart contract solution does not work for the vast majority of Cardano users. One could argue that users will just switch to a smart contract wallet, but will they? Not everyone trusts smart contracts as much as they trust the base Cardano ledger.
  2. How much more efficient is the ledger version vs the smart contract version? The smart contract version has to enforce everything at runtime using very scarce execution units. Conversely, the ledger version would do a lot for free.
  3. How easy is it for dApps to integrate with the smart contract version? With the ledger version, the ledger tells the dApp whether it is in the top level or a sub-level, and makes it easy to access the relevant data at runtime. Wouldn't dApp developers need to do a lot more (error-prone) work to integrate with the smart contract version?

@michele-nuzzi
Copy link

smart contract approach (by definition) does not

Which definition? could you explain it to me why adding a simple input does not work with contracts?

How easy is it for dApps to integrate with the smart contract version?

How hard it is to query one more utxo?

@michele-nuzzi
Copy link

michele-nuzzi commented Jun 30, 2025

How much more efficient is the ledger version vs the smart contract version?

By this argument, plutus should not exist, everything we want to do should be a modification of the ledger, because "we get everything for free"

Wouldn't dApp developers need to do a lot more (error-prone) work to manage all the possibly unbalanced sub-transactions?

With the smart contract version, the app only minds their logic; the babel fee logic is kept separate from the application logic

@michele-nuzzi
Copy link

@fallen-icarus mind you I'm not proposing a smart wallet for users, but only for providers, this solution works for everyone

@fallen-icarus
Copy link
Contributor

Which definition? could you explain it to me why adding a simple input does not work with contracts?

If the user's funds are locked at a pubkey address, signing a redeemer does nothing because the funds are not protected by logic. The user would need to sign the full transaction which is exactly the coordination problem nested transactions is trying to solve. The smart contract approach only works for funds protected by the smart contract.

... I'm not proposing a smart wallet for users ...

That doesn't make sense to me. If the user's funds are not at a smart wallet, how can their funds be spent just by signing a redeemer?

How hard it is to query one more utxo?

I was referring to the on-chain code for the dApp. With the smart contract version, wouldn't the dApp need to analyze the redeemers at runtime just to figure out its own contexts? I'm actually curious if the smart contract approach introduces a new double-satisfaction attack vector that all dApps would need to consider. The ledger would enforce some safeguards for free which takes away some of the security burden for dApp developers.

By this argument, plutus should not exsist, everything we want to do should be a modification of the ledger, because "we get everything for free"

That is not what I'm saying. Consider the Linux Kernel, ubiquitously useful features (e.g., new filesystems) are eventually integrated directly into the kernel while the rest of the features are not. I think the Cardano Ledger should be treated the same way. I don't actually know if Nested Transactions satisfies this high bar; that's why I'm asking these questions.

@michele-nuzzi
Copy link

That doesn't make sense to me. If the user's funds are not at a smart wallet, how can their funds be spent just by signing a redeemer?

Because we are not spending user funds, we are spending the provider funds

Have you even had a look at the proposed smart contract solution before assuming it doesn't work?

image

@fallen-icarus
Copy link
Contributor

Do you realize how aggressive you are?

Because we are not spending user funds, we are spending the provider funds

The Nested Transactions CIP works for both spending user funds and spending provider funds. So it sounds like the smart contract approach indeed does not cover the same use cases. It only covers a subset of use cases.

@michele-nuzzi
Copy link

Do you realize how aggressive you are?

What would you consider an appropriate response to someone who just dismisses your solution without reviewing it?

@michele-nuzzi
Copy link

michele-nuzzi commented Jun 30, 2025

So it sounds like the smart contract approach indeed does not cover the same use cases. It only covers a subset of use cases.

It sounds like you havent reviewed the proposed smart contract solution.

Also this is designed to solve specifically the babel-fee problem

With very few adjustments, the same solution could be applied to your version of p2p swaps with professional market makers

@fallen-icarus
Copy link
Contributor

It sounds like you havent reviewed the proposed smart contract solution.

I actually did review your solution which seems very similar to MicroProofs' bullet. The entity signs Data that represents their sub-tx. Then, this signed Data is aggregated with other signed Data to be submitted in the redeemer for a plutus script. As long as the Data is valid and properly signed, the plutus script will allow spending the funds. But this only works for funds protected by this plutus script!

I even directly quoted you 👇:

Because we are not spending user funds, we are spending the provider funds
-- emphasis mine

You placed this extra constraint! Nested Transactions is also trying to enable spending user funds, not just provider funds. But perhaps I am misunderstanding something so please answer this:

How does your solution support spending funds in a Cardano address that is using only pubkey credentials? This address does not use simple scripts (no multisig) or plutus scripts. It is just a pure pubkey address.

@michele-nuzzi
Copy link

@fallen-icarus The contract only checks for the provider's utxo; that means the pubkey (or script) user is perfectly capable of spending their funds, because the script doesn't care about them.

IT DOES NOT ADD ANY MORE CONSTRAINTS ON THE ORIGINAL TRANSACTION

I hope this answers your question

@fallen-icarus
Copy link
Contributor

Sorry, I wasn't clear. I'm not talking about transaction constraints. I'm talking about use cases. You are saying nested transactions and the smart contract approach cover the same use cases, but only after narrowing the scope to spending provider funds.

Use Case Nested Transaction Smart Contract Approach
Spending User Funds (pubkey only addresses) ✔️
Spending Provider Funds (script addresses) ✔️ ✔️

With nested transactions, users don't need to migrate their funds to smart contract addresses to use sub-transactions. Pubkey-only addresses can spend funds by only signing sub-transactions, too.

@michele-nuzzi
Copy link

Use Case Nested Transaction Smart Contract Approach
Spending User Funds (pubkey only addresses) ✔️ ✔️
Spending Provider Funds (script addresses) ✔️ ✔️

Users don't need to migrate any funds.

I don't know how else to explain it

@fallen-icarus
Copy link
Contributor

If I have 100 ADA at an address like this:

Address (PubkeyCredential spendingKeyHash) (Just $ PubKeyCredential stakingKeyHash)

Please explain how I can spend the 100 ADA by only signing a piece of a redeemer. AFAIU, the ledger does not allow this. I need to sign the entire transaction. @lehins

@michele-nuzzi
Copy link

because you don't sign the redeemer, you only use the redeemer of the provider, and you just sign your transaction

@michele-nuzzi
Copy link

This is getting ridiculous. If you really want, I can explain it in a 2-minute call

@fallen-icarus
Copy link
Contributor

Oh, I think I see the confusion. That's a different use case than what I'm saying. You are imagining the provider creates and signs parts of redeemers and sends them to the relevant end-users. The end-user than submits the final transaction. So the flow of the sub-transaction is: provider --> user.

But what about the end-user signing a sub-transaction and sending the sub-transaction to a provider? This is a different use case that is also supported by Nested Transactions, but not the smart contract approach. An example real world use case is an off-chain market maker: users send sub-transactions representing market orders to the market maker and the market maker then adds their liquidity to fulfill all these market orders in one transaction. Having the market maker sign the sub-transaction and send it to each end-user would be way less efficient and prone to unnecessary UTxO contention. So with Nested transactions, the flow of the sub-transactions can go in either direction: provider <--> user.

@michele-nuzzi
Copy link

Nested transactions would be prone to utxo contention too, that would be mitigated by the data aviablity solution that is implemented in parallel, which would also perfectly work to distribute redeemers.

Additionally, the redeemer can specify an optional expiration time so that the provider can guarantee no contention up to that time (optional just in case of rare edge cases where other contracts may require different timing for their purposes).

provider-> user and user->provider are equivalent. As I said this same solution could be applied to your design with very few changes. The smart contract approach has the added benefit of preserving the user privacy from the provider, which can therefore not censor based on the user transaction.

Provider and user don't have to comunicate at all, the provider just has to make aviable the redeemers by any means, the user just takes them.

In your case the market maker just places his liquidity and the user uses it to fulfil their order (which is how traditional OB MM work)

@fallen-icarus
Copy link
Contributor

provider-> user and user->provider are equivalent.

This is false. With the smart contract approach, end-users cannot spend funds by only signing sub-transactions unless their funds are locked at a smart contract address.

Nested transactions would be prone to utxo contention too

Please don't twist my words. I didn't say there would be no UTxO contention. Provider --> user sub-transactions experience different UTxO contention than user --> provider. The type of contention matters for different use cases.

Most of my use cases (like this video game store) require the ability for end-users to create sub-transactions and send them to providers. As I keep explaining, the smart contract approach only supports this if the end-user has their funds locked at the plutus script address. With nested transactions, the user's funds can remain at a pubkey address.

We can talk more at the upcoming ledger working group, but the assertion that the smart contract approach covers the same use cases is false. As I said, it doesn't work for my use cases.

@michele-nuzzi
Copy link

michele-nuzzi commented Jun 30, 2025

I don't know how you keep interpreting every message of mine as an attack.

Maybe not by this approach, but there is nothing preventing you from exploring some more contract designs, since there is no fundamental capability that nested transactions add to the expression of a transaction.

If you can send a partial tx to the provider certainly you could send some arbitrary JSON/CBOR to the same provider

@lehins
Copy link
Contributor

lehins commented Jun 30, 2025

@lehins we have to be realistic. What is the problem we are trying to solve?

I am being realistic. Babel fees is precisely that: ability to pay fees in something other than ADA. If a user is forced to specify 150% in ADA anyways to pay for the fees for phase2 invalida transaction, then it is not Babel Fees.

There is no user with "no ada" due to minUtxo.

Having few lovelace due to minutxo restriction does not constitute having enough ADA to pay for fees and collateral

The problem we are trying to solve is not "allow someone without ada to transact" because such a user doesn't exist, the problem we are trying to solve is "pay a fee with any token".

In my opinion forcing user to specify collateral is precisely the opposite of ability to pay fee in any token.

Additionally, this problem only exists for simple transfers, where min collateral is less than minUtxo with no tokens for such a simple contract.
With collateral_percent set at 150, a tx that would take 0.2 ADA of fee only requires 0.3 ADA of collateral.

Babel Fee smart contract does not sound that simple that to me that it will cost 0.2 ADA, but I could definitely be wrong here since I do not write smart contracts and I am oblivious to their costs

do you want to tell me the user does not have at least 2 utxos to do a transaction?

Not necessarily that has enough ADA in it to submit a transaction.

do we want to introduce also transactions for the "users that don't have utxos"?

That will unlikely to ever happen 😉 Cardano is a UTxO base blockchain. Even though there is a chance that accounts are on the horizon, a user will always have to spend at least one utxo for a replay protection.

@ch1bo
Copy link
Contributor

ch1bo commented Jul 1, 2025

I'm interested in this proposal for, which may be, a new use case:

As a user, instead of submitting a chain of valid transactions, I would like to submit a top level transaction with a bunch of sub transactions in one go.

Reasons for that my be that this will yield an overall lower inclusion latency. While the overall size will be governed by the maximum transaction size, the cost of validating the batch may be even be lower?

My main point of interest, however, would be the fact that it provides atomicity to multiple transactions and that I can refer to them by a single ID. Is this the case with the current proposal? (From a first look, I'd say yes)

Further context: At least one of the Leios protocol designs, that aim for increased throughput on Cardano, would benefit from being able to refer to groups of transactions (instead of all txs individually).

a batch is required to cover the minimum fees of all transactions. The fees specified in all transactions are always collected.
Individual transactions in a batch do not need to meet the min-fee requirement.

8. The total size of the top-level transaction (including all its sub-transactions) must be less than the `maxTxSize`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems ambiguous - does it mean the total size of the top-level transaction including (naturally) the sub-transaction hashes, or recursively the total size including all the sub-transaction sizes too?

If the latter, that would seem a shame (and would prevent a particular use case in Leios which this margin is too small to contain), and it's not clear why this constraint is required.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would not impact the Leios use case we have been thinking about? In that situation, the max tx size could be bigger (which has all kinds of good properties like reducing potential for conflicts).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that's good - but I'd still like to understand why it has to be limited at all - assuming I have understood correctly that batching is by reference rather than inclusion?

Implied by:
L111: 2. subTxs : ℙ TxId

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Batching is by inclusion, instead of by reference, hence the size limit

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK. thanks. Did I misunderstand the meaning of "TxId" in the definition of subTxs? I had assumed that was a hash.

@lehins
Copy link
Contributor

lehins commented Jul 1, 2025

@ch1bo Nested Transactions in a nutshell means a regular transacttion that includes a list of sub-transactions.
So, each sub-transaction will have its own txId, but it would be possible to uniquely identify all sub-transactions through the top level transaction id.
In other words, it does seem like Nested Transaction would fit your use case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Ledger Proposals belonging to the 'Ledger' category. State: Confirmed Candiate with CIP number (new PR) or update under review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.