Conditional Transactions (EIP-7793) for Amsterdam
What is it?
Conditional transactions are a new transaction type that is only valid at a certain slot and index in a block. For instance, you could create a transaction that is valid only if it is included at the top of block (index 0). The primary motivation is more secure encrypted mempools.
What is the point of encrypted mempools?
Encrypted mempools work by submitting a transaction to the chain in two phases. In slot A the user posts an encrypted transaction onchain, that is sequenced with other encrypted transactions. In slot A+1 the decryption key is revealed and all of the transactions are decrypted and included in the order they were sequenced in at the top of the block. This provide two benefits: frontrunning protection and censorship resistance.
Frontrunning is when someone else sees the contents of my transaction and includes their own transaction ahead of mine based on this information. For example if my transaction is a swap, someone can insert their own transaction first to make a profit at my expense. This is not possible with encrypted mempools: my transaction is encrypted when it is sequenced so does not leak information. Note that this is much stronger than slippage protection, which would simply limit how much I can be exploited by a frontrunner. This can also be used in other contexts, hiding my bid in an auction, or move in a strategy game.
It can also provide censorship resistance guarantees: when I submit my transaction in slot A the builder (or includers) do not know the contents of my transaction, so have no reason to censor it. In slot A+1 it becomes very difficult for the builder to censor my unencypted transaction, since the ciphertext is already on chain everyone can see that the builder is censoring, and they could be slashed within the encrypted mempool protocol (for example).
Why include in Amsterdam?
Encrypted mempools can provide a big UX boost for users by preventing frontrunning, while strengthening the censorship resistance guarantees of the chain!
What is the problem with encrypted mempools?
The problem that exists today is that in slot A+1, there is nothing to enforce that the builder actually includes the decrypted transactions in the sequenced order. This undermines everything, we have a list of encrypted transactions specifying their order, but the builder simply ignores it and reorders the transactions, frontrunning without consequence.
Conditional transactions partially solve this problem, using this new transaction type we can specify that a transaction is only valid at the top of the block, preventing the builder from inserting their own frontrunning transactions ahead of the decrypted ones.
How can it be used in practice?
Conditional transactions alone do not fully solve the problem with encrypted mempools, in practice they must be combined with batched transactions (eg. with EIP-4337).
Without transaction batching we have a problem: if my encrypted transaction is sequenced to be at index 3, I can create a conditional transaction that forces it to be included at index 3. However, what if the builder does include my transaction at index 3, but replaces the transaction at index 2 with their own frontrunning transaction?
This is why batching is needed, all of the decrypted transactions are batched into one single onchain transaction. This allows for smart account code to internally check that the transactions are the ones that are expected, and they are in the correct order. This batched transaction can then be conditional on being included at index 0. If the batched transaction grows too large, it can be split into multiple conditional transactions.
This means we need a batcher, an untrusted entity who bundles all of the decrypted transactions together and submits them to a (trusted) smart contract to verify and execute.
Why is it designed in this way?
Conditional transactions require the desired index and slot to be specified upfront as a field in the transaction. This means that block building is not significantly complicated, the builder can immediately tell where the conditional transactions needs to be included.
The EIP also includes an opcode that returns the transaction index onchain when executed in a conditional transaction. This allows a users smart account to check that the index is correct without needing to trust the batcher.
Isn’t top of block too valuable to be used this way?
The top of the block is valuable due to the opportunity to extract MEV. Since transactions from the encrypted mempool go through an extra slot of latency to reach the chain, they don’t gain this same advantage to extract MEV first. Effectively the new top of block from an MEV perspective, is the first transaction after those from the encrypted mempool.
Are there other applications?
Another potential application of conditional transactions is Ultra tx, as this proposes batching many transactions into one that must be posted at the top of block.