Skip to content
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

feat: hashed cross domain submarine sends #226

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

hamdiallam
Copy link
Contributor

Description

Provide a public utility to conduct hashed cross domain sends, primarily for DeFi applications.


We can take inspiration by replicating a commit / reveal scheme for data sent between chains. Enabling cross chain transactions between contracts where the intent remains hidden until the reveal on the destination chain.

Unlike [Submarine Sends](https://libsubmarine.org/) which also provides the ability to make the commit transaction indistinguishable from a normal value transfer, the funds and commitment have to be accounted for and propogated through the `L2ToL2CrossDomainMessenger` which can allow for an external entinty to differentiate between a hashed cross domain submarine send and not. However this is not a problem since DeFi attacks rely on understanding the intent of the transaction which we show remains masked.

Choose a reason for hiding this comment

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

nit: entinty -> entity

bytes32 commitment = keccak256(payload)
```

By posting just the commitment, **only the the submitting user with knowledge of the preimage would be able to reveal the transaction** when relaying. If this user encounters issues between submission and relay, the preimage for that data is also lost.

Choose a reason for hiding this comment

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

nit: only the the submitting -> only the submitting


By sending the commitment hash between L2s via the L2ToL2CrossDomainMessenger, we gain the ability to privately send transactions. However, submarine sends are typically accompanied with funds with the transaction. i.e Bridge and Swap.

The SuperchainTokenBridge & ETH bridge are designed as single cross chain messages. Thus the cross domain submarine contract needs to be able to receive and escrow sent funds prior to excuting the reveal transaction. Thus, a cross domain submarine transaction requires 2 relays on the destination

Choose a reason for hiding this comment

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

Nit: prior to excuting -> prior to executing

2. Relay message the propogated commitment and details about funds owed to the target.

Sample snippet on how this can work for ETH. Generalizable to SuperchainERC20s

Choose a reason for hiding this comment

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

I am not entirely sure, but it sounds like apps will basically have one submarine contract per chain per app, and they will do submarine sends via this one submarine contract. If this is true (pls confirm), then what happens when there is a race condition on the token amount / swap? e.g. if two users send ETH (from same or diff chain) to the same submarine contract on the one chain, users can have their onward transaction processed out of order. Or is there a baseline assumption that interop txns will be ordered?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good q!

Yep just like how apps integrate with the SuperchainTokenBridge or L2ToL2CrossDomainMessenger, they can integrate with this. Probably would have a handler contracts on both sides that integrates with the DEX

This design retains the same ordering properties of the token bridge and messenger. There is no enforced ordering. Relayers can relay messages in whatever order they would like.

Since the submarine sender specifies the relayer ahead of time (labs likely would provide a public goods one). I would imagine here we would prolly relay in order as much as possible. However this would not be enshrined in the sumbarine contract.

If you wanted to enforce ordering though, you could do that in the handler contract. what are your thoughts?

Copy link

@simplyoptimistic simplyoptimistic Apr 6, 2025

Choose a reason for hiding this comment

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

Ideally ordering should be enforced on the protocol level because any sort of cross chain action that involves an initial token transfer followed by some defi action would have this race condition, meaning each protocol would have to implement this logic. It could be as simple as having certain messages be contingent on a transfer (so until your token transfer passes, we cannot progress). I think this is something hyperlane is going to implement.

Re: the submarine send contract, it would make sense if this could be wrapped together with an interchain account router type feature, as it would mean that crosschain features that require no new contracts could just involve a crosschain transfer followed by multicalls to execute the remainder of the defi logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

because any sort of cross chain action that involves an initial token transfer followed by some defi action would have this race condition

Maybe I misunderstood. The ordering for this part is enforced. The hashed defi action cannot occur before the funds are available in the destination. And this can be batched together so that it does not require separate txs.

Ordering for that is enforced here:

   // Ensure delivery before marking the commitment as pending
   require(messenger.successfulMessages(sentETHMsg));

The ordering that is not enforced is between two unrelated submarine actions.

Can you elaborate on the interchain account feature here? The sender is agnostic of any particular target. So it would be compatible with any crosschain action

Choose a reason for hiding this comment

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

Maybe I misunderstood. The ordering for this part is enforced. The hashed defi action cannot occur before the funds are available in the destination. And this can be batched together so that it does not require separate txs.

Got it, then that's fine. If the transactions are always batched or at least dependent on a prior txn, then race conditions are not an issue.

Can you elaborate on the interchain account feature here? The sender is agnostic of any particular target. So it would be compatible with any crosschain action

The interchain account router allows you to chain arbitrary calls on the destination, e.g. on receiving funds, the contract can swap them for a different asset, and then deposit them into a contract (or something like that). My expectation is that most users that use interop will want the ability to do something like this at least initially, and it would not make sense for each protocol to deploy their own multicall as the recipient of the instructions (i.e. it should be folded into the interop contracts). Does that kind of make sense?

This means that when interop ships, it would be easy for an app developer to create a webapp/contract that allows users to bridge cross chain then do things on other chains, without having to deploy any contracts on other chains at all. They could craft payloads that they can submit on any origin chain, which could be executed on any destination chain against any contracts that already exist on that chain.

Of course, as protocols more heavily integrate interop, this will become less relevant. But at least it lessens the barrier to doing things crosschain on day 1.


The salt can ensure commitments are always unique. However it is the responsibility of the dapp to ensure this. It's already unlikely in DeFi that calldata might be the exact same as they depend on token inputs and minimum expected outputs. And even if they are the same, they must be pending during the same time window.

However an attacker that realizes that a dapp is using the same salt could try to fontrun some expected (target,message) combos with submarine sends that where the target always fails. All this would achieve in the current sample code snippet is halting delivery of submarine sends with the same commitment (already unlikely).

Choose a reason for hiding this comment

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

nit: fontrun -> frontrun


By posting just the commitment, **only the the submitting user with knowledge of the preimage would be able to reveal the transaction** when relaying. If this user encounters issues between submission and relay, the preimage for that data is also lost.

To solve for this, the payload is encrypted and posted as calldata to the submitting transaction. By using ECDH, Elliptic Curve Diffie-Hellman, the data can be encrypted against any public key, allowing for the user to designate a 3rdparty to conduct the relay on their behalf.
Copy link

Choose a reason for hiding this comment

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

I'd suggest leaving this preimage posting unspecified. If a user wants to post it encrypted onchain they can, but many implementations may prefer an out of band dissemination

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea that's a good point! This all can be encoded as opaque bytes represented with 1 argument. Everything else should be good


We can take inspiration by replicating a commit / reveal scheme for data sent between chains. Enabling cross chain transactions between contracts where the intent remains hidden until the reveal on the destination chain.

Unlike [Submarine Sends](https://libsubmarine.org/) which also provides the ability to make the commit transaction indistinguishable from a normal value transfer, the funds and commitment have to be accounted for and propogated through the `L2ToL2CrossDomainMessenger` which can allow for an external entinty to differentiate between a hashed cross domain submarine send and not. However this is not a problem since DeFi attacks rely on understanding the intent of the transaction which we show remains masked.

Choose a reason for hiding this comment

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

nit: propogated => propagated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants