Skip to content

Latest commit

 

History

History
102 lines (64 loc) · 12.6 KB

ARCHITECTURE.md

File metadata and controls

102 lines (64 loc) · 12.6 KB

Architecture

This document aims to provide a high-level overview of Fuel's token bridge and its current operation.

Concepts

Before delving into the details, let's understand a few key concepts that will be referenced throughout this document:

  • Layer 1 (L1): An EVM blockchain, namely Ethereum.
  • Layer 2 (L2): The Fuel blockchain will sometimes be referred as the Layer 2 or L2.
  • Fuel block: a block of the Fuel blockchain, generated by sequencers. It contains transactions, but also messages, outgoing and relayed.
  • Fuel root block: the last block of a Fuel epoch.
  • Fuel epoch: A group of Fuel blocks, packed together and identified by the last block of the epoch.
  • Outgoing messages: Messages that are generated in the L1 blockchain that must be sent to L2 entities.
  • Relayed messages: Messages that are generated in the L2 (Fuel) blockchain that must be sent to L1 entities.
  • Fuel sequencers: Entities that process L2 transactions and keep the ledger updated.
  • L1 Commits: Transactions on the L1 that start the finalization process of a Fuel epoch.
  • Finality: State of commits by which the commit cannot be changed, it is considered honest and immutable - final. When an epoch is committed, a clock starts. If the commit is correct, time will pass and the epoch will be final - it cannot be reverted or changed. If the commit is not correct, an honest party can challenge it.
  • Block comitter: entity responsible for listening to finished epochs from the Fuel Blockchain and comitting these epochs to the FuelChainState contract.
  • FuelChainState contract: L1 Smart contract that holds epoch information.
  • FuelMessagePortal contract: L1 Smart contract that is able to validate relay messages from Fuel Blocks that have been committed to the state contract, and relays those messages to the corresponding entities in L1
  • Layer 1 Bridge smart contract: L1 smart contract that holds L1 tokens. Upon user deposits, it generates an message for the L2 counterpart to mint the associated L2 token.
  • Layer 2 Bridge smart contract: L2 (Fuel) smart contract that mints L2 tokens when receiving messsages from the L1 counterpart. Similarly, burns L2 tokens and generates a withdrawal message for the L1 contract to release L1 tokens to their rightful owner.
  • Deposit: User action by which some L1 tokens are locked in the L1 bridge smart contracts, minting the same amount in the L2 chain.
  • Withdrawal: User action by which some L2 tokens are burnt in the L2 bridge smart contracts, releasing the burnt amount in the L1 chain.

Bridge flow

Fuel 's bridge system is built on a message protocol that allows to send (and receive) messages between entities located in two different blockchains, namely the L1 (Ethereum or EVM) and L2 (Fuel blockchain). The system features sending messages in both directions (L1 to L2, and L2 to L1), though the mechanism involved for each direction is different. It can be derived that if the entities receiving these messages are capable of interpreting them, some actions can be executed.

In the case of the bridge system, there are two scenarios:

  1. The deposit scenario: a L1 smart contract can send a message to another L2 smart contract upon receiving a deposit of tokens. The L2 smart contract will receive, process and validate this message, and mint an equivalent amount of tokens in the L2
  2. The withdrawal scenario: the holder of L2 tokens can burn them, and in doing so, generate a message from the L2 smart contract to the L1 smart contract that held bridged tokens. The L1 smart contract can process the message and release the L1 tokens back to an address, defined in the message generated in the L2 by the user, and presumably controlled by this same user.

In the case of the deposit scenario, the message is relayed from the L1 to the L2 by the sequencer set of the Fuel blockchain. The withdrawal messages, on the other hand, are indirectly included in the commits that assert the finality of the Fuel blockchain in the L1, which means that once the history of the Fuel ledger is considered final, immutable and anchored to the L1, any user can execute withdrawal messages in the L1 blockchain.

Block committing

The Fuel blockchain aims to be scalable, and thus is able to generate blocks at a faster rate than other blockchains, without compromising on its security. It does so by inheriting the security of the L1 it is anchored to. The mechanism allowing this is an hybrid optimistic-ZK rollup (WIP). Blocks generated in the Fuel blockchain are grouped in epochs (e.g. an epoch can group together 10800 blocks), and epochs are identified and summarized in the last block of said epoch. This block can be committed to the L1 blockchain with a transaction to the FuelChainState contract, and will be accepted optimistically (i.e. the commit is considered valid unless proven otherwise - validation of the blocks are not considered in the scope of this document). The commit will be registered with the timestamp of the L1 blockchain. Then, once a certain time period has passed, the commit (along with the block) will be considered final.

Block Committing

Message passing from L1 to L2

The Message Portal contains a sendMessage function that can be called by any entity on the L1 blockchain. This function will emit an event to be picked up by Fuel 's sequencers, containing the message payload. The sequencers will include said message in the following blocks of the L2 blockchain, by adding an UTXO that reflects the original message and payload. This UTXO can be "spent" (i.e. delivered) by any party on the L2 blockchain.

L1 Deposit

A deposit operation is an example of message passing from L1 entities to L2 entities. The user will send a transaction to deposit an asset in a L1 bridge contract, which will in turn emit a message through the FuelMessagePortal to be picked up by the Fuel blockchain 's sequencer. Sequencers will include this deposit message as part of an UTXO that can be spent by any entity, but forcing the condition of being delivered to the L2 bridge contract. Once the UTXO is "spent" (delivered), this last contract will have the capability of processing these messages, validating that their sender is the L1 bridge contract, and then proceeding to mint an equivalent asset and amount in the Fuel blockchain to the one originally depositted in the L1. Then, the minted assets become available to the user in the L2.

TODO update this diagram L1 Deposit

You can follow the actual implementation of the message processing flow via:

Message passing from L2 to L1

The mechanism that implements messaging from L2 to L1 can be more convoluted; bear with us.

Any user on the L2 can trigger transactions that generate a message. This message is included as part of the Fuel block, and its inclusion can be proven by verifying a Merkle root in the block header that commits to a Merkle tree containing the message. The block hash is derived, among other fields, from this root.

Fuel blocks are packed and committed together by the mechanism described two sections above, block comitting. A Fuel epoch will be committed at the Chain State contract with the last block of the epoch, namely the Fuel root block. This block features another Merkle root that commits to a tree consisting of the block hashes of the epoch. Again, the hash of this root block is derived, among other elements, from this root.

Once the committed epoch has finalized, an user in the L1 blockchain can prove that the original message was included in the finalized epoch:

  • First, it is needed to prove that a certain block (identified by its block hash) exists in the committed epoch. This is done with a Merkle proof.
  • Once proven that the block exists, by the same mechanism, it is possible to prove that the message exists as part of the block.

An user can request proofs of inclusion of both the block inside the epoch, and the message inside the block, to the L2, then attach those proofs on a call to Message Portal 's relayMessage. The portal will check that the proofs are correct and that the finalization status of the epoch, then proceed to unpack the payload of the message, that should contain execution instructions.

L2 (Fuel) Withdrawal

A bridge withdrawal is an example implementation of message passing from L2 entities to L1 entities.

The user will start the process by signaling a withdrawal transaction to the L2 Bridge Contract, which will burn the tokens and generate a message to be included in a Fuel block, with recipient to the L1 Bridge Contract. This message will be relayed later on by means of the block committer and the Message Portal.

Once the transaction has been included in the Fuel blockchain, the user will need to await two events:

  • First, the Fuel blockchain will need to close the epoch. The epoch will be committed to the L1 blockchain in the Chain State contract. It will be possible to prove the inclusion of all the blocks in the epoch with the Merkle root of the Fuel root block (commit).
  • Then, once the epoch has been committed, it is needed to wait for its finalization.

After finality has been reached for the epoch that includes the block where the withdrawal transaction was signaled, the user can request the proofs of inclusion of both the message in the Fuel block, and the Fuel block in the Fuel epoch. The user will send a transaction call to the Message Portal 's relayMessage function that will check the attached proofs and the finalization status of the epoch that the message belongs to, then proceed to unpack the payload of said message, that should contain an execution instruction to call finalizeWithdrawal in the L1 Bridge Contract, releasing the L1 locked tokens.

L2 Withdrawal

You can follow the implementation of this flow via:

Decimals adjustment

Easing the operation and participation of light clients in the network without compromising on security is a key principle in Fuel. In that sense, Fuel strives to minimize the size of the information that is exchanged between peers through the protocol. One of the design decisions furthering that goal is the use of 64 bits (u64) to code the balances that are bridged from L1 to L2. The most popular token standard, ERC20, codes the amounts with 256 bits. If the amount transferred from L1 to L2 surpasses the capacity of Fuel to mint the L2 counterpart, a refund message will be generated, that will allow the user to retrieve the originally depositted amount in L1.

Additionally, it is a de-facto practice in the space to use 18 decimals to represent the token, whereas in Fuel, 9 decimals are used to represent amounts under the unit. This means that there is a potential loss of precision when it comes to translating L1 amounts to L2 amounts, as the user could lose some dust amounts between bridging operations. Ideally, this limitation could be worked around as long as the deposits initiated in L1 do not specify amounts greater than 9 decimals (i.e. 1.0000000010 does not lose amounts, 1.0000000011 would lose 0.0000000001). DApps that enable bridge operations should observe this limitation and truncate the amounts to avoid loss of precision.