-
Notifications
You must be signed in to change notification settings - Fork 148
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
Sovereign Chains Cross-Chain Execution #1033
Open
andreiblt1304
wants to merge
26
commits into
development
Choose a base branch
from
cross-execution
base: development
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
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
f0ca287
Added Cross-Chain Execution docs
andreiblt1304 8c4045b
Removed some info and added page to sidebars.js
andreiblt1304 d8c1948
Renamed file and added separate category
andreiblt1304 00040de
Typo fix
andreiblt1304 4d2092c
Removed example page
andreiblt1304 f7aae1c
Added description for main SCs
andreiblt1304 68a68c2
Renamed title for to-sovereign file
andreiblt1304 5af921e
Renamed title for from-sovereign file
andreiblt1304 6f7c324
Made first Cross-Chain execution page more clear
andreiblt1304 b9f9346
Updated photos
andreiblt1304 fbf6d13
Fixes after review
andreiblt1304 dccc49c
Typos
andreiblt1304 463a9f5
Fixes after review
andreiblt1304 902bfa1
Added Header-Verifier documentation
andreiblt1304 eef67bb
Updated diagrams
andreiblt1304 9ecd4a6
More fixes
andreiblt1304 f6a9cfc
Fix after review
andreiblt1304 0f981e1
Spell checker
andreiblt1304 0c1cc40
Fixes after review
andreiblt1304 19a4028
Merge branch 'development' into cross-execution
andreiblt1304 5eec40f
Modified introduction
andreiblt1304 41d3cae
Modified introduction
andreiblt1304 d7eaea7
Moved the ESDT-Safe contract at the top
andreiblt1304 12ad601
Modified from-sovereign docs
andreiblt1304 0f7fcfa
Fix after review
andreiblt1304 d12a4ce
Typo
andreiblt1304 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 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,42 @@ | ||
# Introduction | ||
|
||
When we take a look at the blockchain industry, we observe a segregated ecosystem lacking cohesion, interoperability, teamwork. Many strive to reach the top independently. The vision lead to the Blockchain Revolution, knows as “Web3” — a new era of the internet that is user-centered, emphasizing data ownership and decentralized trust. | ||
|
||
Sovereign Chains will dismantle the barriers between isolated blockchain networks by allowing smart contracts to seamlessly interact across different Sovereign Chains and the main MultiversX chain. | ||
This cross-chain interoperability is crucial for fostering an environment where decentralized apps (dApps) can utilize functionalities or assets from across the ecosystem. | ||
|
||
## What is Cross-Chain Execution? | ||
|
||
Cross-Chain execution is the ability of smart contracts or decentralized applications on one blockchain to invoke actions on another blockchain. This feature allows for seamless communication and interaction between different blockchain networks, enabling developers to build applications that are chain agnostic. | ||
|
||
|
||
## Cross-Chain Execution within Sovereign Chains | ||
|
||
This feature is enabled by using multiple smart contracts, each one with its unique role and set of functionalities. The current Sovereign Chain suite consists of three main contracts, here is the high-level description for some of the cross chain smart contracts: | ||
|
||
#### ESDT-Safe | ||
The *ESDT-Safe* Smart Contract performs all the heavy lifting. This contract facilitates the cross-chain transfer between either any Sovereign Chain and the MultiversX mainchain or the other way around. | ||
|
||
There are two modules implemented for this contract: [*From Sovereign*](from-sovereign.md), [*To Sovereign*](to-sovereign.md) and two important endpoints: [`execute_operation`](from-sovereign.md#executing-an-operation), [`deposit`](to-sovereign.md#deposit-tokens). | ||
|
||
:::note | ||
The naming for those modules has been chosen this way to represent the direction of the execution. In the following sections we will be referring to `FromSovereign` as the execution starts within the Sovereign Chain and `ToSovereign` as the destination of the execution is a Sovereign Chain. | ||
::: | ||
|
||
#### Fee-Market | ||
Since every Sovereign Chain will have a customizable fee logic, it was paramount that this configuration had to be separated into a different contract. Rules such as: fee per transferred token, fee per gas unit and users whitelist to bypass the fee are set here. This contract is also present in the MultiversX mainchain and in any Sovereign Chain. | ||
|
||
#### Header-Verifier | ||
When any transaction happens inside a Sovereign Chain is called and *operation*. The main role of this contract is to verify operations. They have to be signed by the validators of the Sovereign Chain. If the operation is successfully verified it will be registered and then can be executed by the ESDT-Safe contract. All the *BLS keys* of the validator will be stored inside this contract. | ||
|
||
:::note | ||
The source for the smart contracts can be found at the official [MultiversX Sovereign Chain SCs repository](https://github.com/multiversx/mx-sovereign-sc). | ||
::: | ||
|
||
#### Sovereign Bridge Service | ||
This feature facilitates the execution of outgoing operations. This service is an application that receives Sovereign operations. After that, it will call the `execute_operation` endpoint from the instance of the ESDT-Safe contract that is deployed on the MultiversX mainchain. The registration and execution of operations looks like this: | ||
|
||
- For N operations there is only one [register transaction](from-sovereign.md#registering-a-set-of-operations) inside the Header-Verifier smart contract. | ||
- N transactions for the [execution](from-sovereign.md#executing-an-operation) of N operations inside the ESDT-Safe smart contract, one execution transaction per operation. | ||
|
||
> There can be one or more services deployed in the network at the same time. |
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains 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,158 @@ | ||
# Execution starting from a Sovereign Chain | ||
![From Sovereign](../../static/sovereign/from-sovereign.png) | ||
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
For the user — whether an External Owned Account (EOA) like a user wallet or another smart contract — procedure is simple. An address will be able to perform a multi tokens transfer with various types of tokens: | ||
- Fungible Tokens | ||
- (Dynamic) Non-Fungible Tokens | ||
- (Dynamic) Semi-Fungible Tokens | ||
- (Dynamic) Meta ESDT Tokens | ||
|
||
When making the deposit, the user specifies: | ||
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. A destination address on the Sovereign Chain | ||
2. `TransferData` if the execution contains a smart contract call, which contains gas, function and arguments | ||
|
||
Each action that can be executed remotely through this contract is called an *Operation*. The endpoint responsible for executing those operations is called `execute_operations`. | ||
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Sovereign Chain to Main Chain transfer flow | ||
1. User deposits token to the ESDT-Safe smart contract on Sovereign. | ||
2. Outgoing *Operations* are created at the end of the round. | ||
3. Validators sign all the outgoing *Operations*. | ||
4. Leader sends *Operations* to the bridge service. | ||
5. Bridge service sends the *Operations* to the Header-Verifier for registration and verification, and then to ESDT-Safe for execution. | ||
6. At the end of the execution success/fail, a confirmation event will be added which will be received in sovereign through the observer and then the cross chain transfer will be completed. | ||
## Executing an Operation | ||
|
||
```rust | ||
#[endpoint(executeBridgeOps)] | ||
fn execute_operations( | ||
&self, | ||
hash_of_hashes: ManagedBuffer, | ||
operation: Operation<Self::Api> | ||
) | ||
``` | ||
- `hash_of_hashes`: hash of all hashes of the operations that were sent in a round | ||
- `operation`: the details of the cross-chain execution | ||
|
||
Since this endpoint can be found inside the _From Sovereign_ module, we are safe to say that the cross-chain execution will start from within a Sovereign Chain. The execution flow of this endpoint is at follows: | ||
|
||
1. Calculate the hash of the *Operation* received as a parameter. | ||
2. Verify that the given *Operation’s* hash is registered by the Header-Verifier smart contract. | ||
3. Mint tokens or get them from the account. | ||
4. Distribute the tokens. | ||
5. Emit confirmation event or fail event if needed. | ||
|
||
As the 2nd point specifies, the [Header-Verifier](#header-verifier-sc) smart contract plays an important role in the cross-chain execution mechanism. In this section there will also be a description for the important endpoints within this contract. | ||
|
||
:::note | ||
The source code for the endpoint can be found [here](https://github.com/multiversx/mx-sovereign-sc/blob/main/esdt-safe/src/from_sovereign/transfer_tokens.rs). | ||
::: | ||
|
||
### Important structs | ||
```rust | ||
#[derive(TopEncode, TopDecode, NestedEncode, NestedDecode, TypeAbi, ManagedVecItem, Clone)] | ||
pub struct Operation<M: ManagedTypeApi> { | ||
pub to: ManagedAddress<M>, | ||
pub tokens: ManagedVec<M, OperationEsdtPayment<M>>, | ||
pub data: OperationData<M>, | ||
} | ||
``` | ||
|
||
- `to`: specifies the destination of the *Operation* | ||
- `tokens`: represents one or more token transfers associated with the operation | ||
- `data`: encapsulates additional instructions or parameters that guide the execution of the operation | ||
|
||
```rust | ||
pub struct OperationEsdtPayment<M: ManagedTypeApi> { | ||
pub token_identifier: TokenIdentifier<M>, | ||
pub token_nonce: u64, | ||
pub token_data: EsdtTokenData<M>, | ||
} | ||
``` | ||
|
||
This struct describes a single token transfer action within an *Operation*. Each Operation can have one or more of such payments, with that enabling the transfer of a variety of tokens during a cross-chain transaction. | ||
|
||
- `token_identifier`: used for the identification of the token | ||
- `token_nonce`: if the token is Non-Fungible or Semi-Fungible, it will have a custom nonce, if not the value will be 0 | ||
- `token_data`: a structure holding metadata and other token properties | ||
|
||
```rust | ||
pub struct OperationData<M: ManagedTypeApi> { | ||
pub op_nonce: TxId, | ||
pub op_sender: ManagedAddress<M>, | ||
pub opt_transfer_data: Option<TransferData<M>>, | ||
} | ||
``` | ||
|
||
`OperationData` encapsulates the needed information for the *Operation* that needs to be executed. This isn’t just another data definition, we’ve already seen data-related fields elsewhere. Instead, it centralizes the contextual information that *Operation* needs before, during, and after execution. | ||
|
||
- `op_nonce`: is used for the identification of each *Operation* | ||
- `op_sender`: represents the original sender of the *Operation* | ||
- `opt_transfer_data`: an optional `TransferData` field, when present, contains details about the cross-chain execution of another Smart Contract | ||
|
||
```rust | ||
pub struct TransferData<M: ManagedTypeApi> { | ||
pub gas_limit: GasLimit, | ||
pub function: ManagedBuffer<M>, | ||
pub args: ManagedVec<M, ManagedBuffer<M>>, | ||
} | ||
``` | ||
|
||
`TransferData` represents the description of the remote execution of another Smart Contract. | ||
|
||
- `gas_limit`: specifies the needed gas for the execution of all other endpoints. | ||
- `function`: the name of the endpoint that will be executed. | ||
- `args`: the arguments for the calls. | ||
|
||
:::note | ||
The source code for structures can be found [here](https://github.com/multiversx/mx-sovereign-sc/blob/main/common/transaction/src/lib.rs) | ||
::: | ||
|
||
|
||
## Header-Verifier SC | ||
|
||
As mentioned in the [Introduction](cross-chain-execution.md) the Header-Verifier smart contract is responsible to verify signatures, store the *BLS Keys* of the validators and register incoming *Operations*. | ||
|
||
### Registering a set of *Operations* | ||
```rust | ||
#[endpoint(registerBridgeOps)] | ||
fn register_bridge_operations( | ||
&self, | ||
signature: BlsSignature<Self::Api>, | ||
bridge_operations_hash: ManagedBuffer, | ||
operations_hashes: MultiValueEncoded<ManagedBuffer>, | ||
) | ||
``` | ||
|
||
Any *Operation* before being executed has to be registered in this smart contract. The reason behind this is that the hash will be verified and it will be locked until the operation is executed by the ESDT-Safe contract. | ||
|
||
The registering endpoint operates as follows: | ||
1. Verifies that `bridge_operations_hash` is not found in the `hash_of_hashes_history` storage mapper, otherwise it will return an error. | ||
2. Verifies that the hash of all `operations_hashes` matches the `bridge_operations_hash, otherwise, the endpoint will return an error. | ||
3. All `operations_hashes` are stored in the smart contract's storage with the status OperationsHashStatus::NotLocked. | ||
4. The `bridge_operations_hash` is added to the `hash_of_hashes_history` storage mapper. | ||
|
||
```rust | ||
#[endpoint(lockOperationHash)] | ||
fn lock_operation_hash(&self, hash_of_hashes: ManagedBuffer, operation_hash: ManagedBuffer) | ||
``` | ||
|
||
The Header-Verifier has a system in place for locking *Operation* hashes. Locking those registered hashes prevents any unwanted behaviour when executing or removing an *Operation* hash. Remember that the execution of *Operations* can only be done by the ESDT-Safe smart contract. This endpoint when called will follow this flow: | ||
|
||
1. Check if the caller is the ESDT-Safe smart contract. | ||
2. Check if the *Operation* is registered. | ||
3. If the hash is not locked set the status in the storage as locked or else return panic. | ||
|
||
:::note | ||
The hash can be in two different states: `OperationHashStatus::NotLocked` or `OperationHashStatus::Locked` | ||
::: | ||
|
||
```rust | ||
#[endpoint(removeExecutedHash)] | ||
fn remove_executed_hash(&self, hash_of_hashes: &ManagedBuffer, operation_hash: &ManagedBuffer) | ||
``` | ||
|
||
After registering and executing an *Operation* the status of the hash associated to it must be removed from the Header-Verifier's internal storage. This endpoint will be called by the ESDT-Safe smart contract after the execution of the *Operation* is successful. The steps are pretty clear: | ||
|
||
1. Check if the caller is the ESDT-Safe smart contract. | ||
2. Remove the status of the hash from storage. | ||
|
This file contains 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,54 @@ | ||
# Execution going to a Sovereign Chain | ||
![To Sovereign](../../static/sovereign/to-sovereign.png) | ||
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The ability to transfer tokens from the Main Chain to any Sovereign Chain is essential, since every Sovereign can connect to the Main MultiversX Chain. As a result, the customizable Sovereign can leverage any token available on the default network. | ||
|
||
The transfer of tokens is done by the *ESDT-Safe* contract after calling the `deposit` endpoint inside the `to-sovereign` module. | ||
|
||
## Main Chain deposit to Sovereign Chain transfer flow | ||
1. User deposits the tokens he wishes to transfer in the ESDT-Safe contract deployed on the Main Chain. | ||
2. An observer is monitoring the Main Chain. | ||
3. Sovereign network receives extended shard header. | ||
4. Incoming transactions processor handles and processes the new transaction. | ||
|
||
### Deposit Tokens | ||
```rust | ||
#[payable("*")] | ||
#[endpoint] | ||
fn deposit( | ||
&self, | ||
to: ManagedAddress, | ||
optional_transfer_data: OptionalValueTransferDataTuple<Self::Api>, | ||
) | ||
``` | ||
|
||
One key aspect of cross chain transfers from MultiversX Main Chain to a Sovereign Chain is being able to transfer tokens and also execute a smart contract call within single transaction. The `#[payable("*")]` annotation means that the endpoint can receive any tokens that will transferred. If those tokens are from a Sovereign Chain they will be burned otherwise they will be saved in the Smart Contract`s account. The checks enabled for the transfer of tokens are the following: | ||
|
||
- If the token is whitelisted or not blacklisted, in that case the tokens can be transferred. | ||
- If the fee is enabled, the smart contract assures that the fee is paid. | ||
- If there are maximum 10 transfers in the transaction. | ||
|
||
If the deposit also includes the `optional_transfer_data` parameter it will also have some extra checks regarding the cross-chain execution of endpoints: | ||
|
||
axenteoctavian marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- The gas limit must be under the specified limit. | ||
- The endpoint that has to be executed is not blacklisted. | ||
|
||
|
||
At the end of the `deposit` endpoint, all the extra tokens will be refunded to the caller and an event will be emitted since the bridging process is complete. | ||
|
||
|
||
```rust | ||
#[event("deposit")] | ||
fn deposit_event( | ||
&self, | ||
#[indexed] dest_address: &ManagedAddress, | ||
#[indexed] tokens: &MultiValueEncoded<MultiValue3<TokenIdentifier, u64, EsdtTokenData>>, | ||
event_data: OperationData<Self::Api>, | ||
) | ||
``` | ||
|
||
This log event will emit the destination address and the tokens which will be transferred to the Sovereign Chain. | ||
|
||
:::note | ||
Here is the [link](https://github.com/multiversx/mx-sovereign-sc/blob/main/esdt-safe/src/to_sovereign/create_tx.rs) to the `deposit` endpoint. | ||
::: |
This file contains 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
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.
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.
I would say we need to add some context about the bridge service because it's needed for my next comments