-
Notifications
You must be signed in to change notification settings - Fork 49
Proposal native bridge #2406
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
tudor-malene
wants to merge
2
commits into
main
Choose a base branch
from
tudor/proposal_native_bridge
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Proposal native bridge #2406
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # Proposal for Message Bus native ETH handling | ||
|
|
||
| In the current implementation we have a Message Bus (MB) that acts as: | ||
|
|
||
| 1. A transport layer between Ten and Ethereum of generic messages of the form: | ||
| ```solidity | ||
| event LogMessagePublished | ||
| ( | ||
| address sender, | ||
| uint64 sequence, | ||
| uint32 nonce, | ||
| uint32 topic, | ||
| bytes payload, | ||
| uint8 consistencyLevel, | ||
| ); | ||
| ``` | ||
|
|
||
| where the `payload` is the message arbitrarily encoded by the top-of-stack bridge. | ||
| For example an "ERC20" transfer command to be executed by the ERC20 contract. | ||
|
|
||
| 2. A "native ETH bridge" between Ethereum and TEN. | ||
|
|
||
| The MB owns native ETH on the Ethereum side and will dispense it to the receiver when receiving a message like this: | ||
| ```solidity | ||
| event ValueTransfer | ||
| ( | ||
| address indexed sender, | ||
| address indexed receiver, | ||
| uint256 amount, | ||
| uint64 sequence | ||
| ); | ||
| ``` | ||
| On TEN, the MB does not own ETH, but the MB is a special "System contract", and the platform itself mints and burns ETH | ||
| on messages such as this. | ||
|
|
||
|
|
||
| ```plantuml | ||
| @startuml | ||
| 'https://plantuml.com/sequence-diagram | ||
|
|
||
| title Current Ten->Ethereum native value withdrawal flow | ||
| autonumber | ||
|
|
||
| Alice -> TEN: Calls "EthereumBridge.sendNative" with 0.1Eth | ||
| TEN --> TEN: Emit MB `ValueTransfer` event encoding the VT (E1) | ||
|
|
||
| TEN -> Ethereum: Rollup with Xchain MTreeRoot (R1) | ||
|
|
||
| Alice -> Ethereum: Call "CrossChain.extractNativeValue" with E1 as parameter. (This is the "Relay" step) | ||
| Ethereum -> Ethereum: Check E1 against R1 (Call the Message Bus contract) | ||
| Ethereum -> Ethereum: Move native value from the MB to Alice's account (`receiver.call{value: amount}("");`) | ||
| note bottom | ||
| Alice - can be another smart contract | ||
| end note | ||
| @enduml | ||
| ``` | ||
|
|
||
| ## Requirements | ||
|
|
||
| 1. Deposit and Withdraw native ETH into EOA. | ||
|
|
||
| 2. Deposit and Withdraw native ETH into smart contracts by calling custom functions. | ||
| - This is required by liquidity bridges, who are DAOs that have to pay into a counterpart crosschain smart contract. | ||
| - Currently, we don't support it. We could in theory by adding a second Proof. | ||
| - Authenticate the "sender". The receiving SC needs to know who or what is sending this value. (Stefan - currently how do we achieve this?) | ||
|
|
||
| # Proposal | ||
|
|
||
| The proposal has two main differences from the existing implementation. | ||
|
|
||
| 1. Move the native value held on the L1 from the MB to the "Reference Bridge" (TenBridge) | ||
| 2. Remove the ``ValueTransfer`` and encode the value transfer on top of ``LogMessagePublished`` | ||
|
|
||
| The native value bridge will become a top-of-stack implementation from the point of view of the MB. | ||
| The MB will only be responsible with the transport layer. | ||
|
|
||
|
|
||
| ```plantuml | ||
| @startuml | ||
| 'https://plantuml.com/sequence-diagram | ||
|
|
||
| title Proposed Ten->Ethereum native value withdrawal flow | ||
| autonumber | ||
|
|
||
| Alice -> TEN: Calls "EthereumBridge.sendNative" with 0.1Eth | ||
| TEN --> TEN: Encode the value transfer as a xchain message | ||
| TEN --> TEN: Emit MB `LogMessagePublished` event encoding the VT (E1) | ||
|
|
||
| TEN -> Ethereum: Rollup with Xchain MTreeRoot (R1) | ||
|
|
||
| Alice -> Ethereum: Call "TenBridge.extractNativeValue" with E1 as parameter. (This is the "Relay" step) | ||
| Ethereum -> Ethereum: Check E1 against R1 (Call the Message Bus contract and authenticate the message) | ||
| Ethereum -> Ethereum: Check that the message originated from the `"EthereumBridge"` (LogMessagePublished.sender=address(EthereumBridge)) | ||
| Ethereum -> Ethereum: Decode the `LogMessagePublished.payload` into a ValueTransfer(vt) struct | ||
| Ethereum -> Ethereum: Move native value from the MB to Alice's account (`receiver.call{value: vt.amount}("");`) | ||
|
|
||
| @enduml | ||
| ``` | ||
|
|
||
| The ``LogMessagePublished.payload`` is a serialised | ||
| ```solidity | ||
| struct ValueTransfer { | ||
| uint256 amount; | ||
| address recipient; | ||
| } | ||
| ``` | ||
|
|
||
| The ``TenBridge`` contract living on Ethereum, that owns all the native ETH can check the following when Alice attempts to withdraw funds: | ||
| 1. That the xchain message she presents is valid (by checking the Mtree) and not consumed already. | ||
| 2. That the message originated from the TEN ``EthereumBridge`` contract. | ||
|
|
||
| Note: In this version we do not support: ```receiver.call{value: vt.amount}(calldata);``` | ||
| We only support plain value transfers. | ||
|
|
||
| Stefan | ||
| - why is this not authenticated | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The authentication only matters when you are calling payable functions:
receiver.call{value: amount}(calldata)
The value transfer even right now is not authenticated - it directly calls a receiver and gives the amount; There is no way for the receiver to ask who is the cross chain sender, which is fine if all you ever do is receiver.call{value:amount}("")
The authentication issue is when you want to know who is the msg.sender on the other network as the msg.sender on the receiving network is non reliable. As to why would one ever need that to be authenticated, can't think of an example when exactly this is going to be necessary, but if the call is composed through a messenger that info will be exposed through the crossChainSender() function.
There are some contracts that I've seen who revert in their receive() methods and only allow for payable calls with calldata, that might need such authentication