Skip to content

Commit

Permalink
doc: update bridge documentation (#880)
Browse files Browse the repository at this point in the history
* doc: update bridge documentation

* doc: remove duplicates

* doc: remove MintTransactionExpired event which not used

* typos and automatic formatting

* events rephrasing

* clarify expired transaction in flow

* adding some details in STELLAR -> TFCHAIN flows

* doc: review adjusments

---------

Co-authored-by: renauter <renauter@gmail.com>
  • Loading branch information
sameh-farouk and renauter authored Nov 1, 2023
1 parent c6cd4f3 commit 38ea787
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 14 deletions.
114 changes: 105 additions & 9 deletions bridge/docs/bridging.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ This document will explain how you can transfer TFT from TF Chain to Stellar and

## Prerequisites

- Threefold Connect application or any other Stellar wallet
- A running bridge and bridge wallet address
* Threefold Connect application or any other Stellar wallet
* A running bridge and bridge wallet address

## Stellar to TF Chain

Expand All @@ -17,20 +17,116 @@ Transfer the TFT from your Stellar wallet to bridge wallet address that you conf

We also enabled deposits to TF Grid objects. Following objects can be deposited to:

- Twin
- Farm
- Entity
- Node
* Twin
* Farm
* Entity
* Node

To deposit to any of these objects, a memo text in format `object_objectID` must be passed on the deposit to the bridge wallet. Example: `twin_1`.
To deposit to any of these objects, a memo text in format `object_objectID` must be passed on the deposit to the bridge wallet. Example: `twin_1`.

To deposit to a TF Grid object, this object **must** exists. If the object is not found on chain, a refund is issued.

## TF Chain to Stellar

Browse to https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics , select tftBridgeModule and extrinsic: `swap_to_stellar`. Provide your stellar target address and amount and sign it with your account holding the tft balance.
Browse to https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Ftfchain.grid.tf#/extrinsics (for mainnet), select tftBridgeModule and extrinsic: `swap_to_stellar()`. Provide your stellar target address and amount and sign it with your account holding the tft balance.
Again, a withdrawfee of 1 TFT will be taken, so make sure you send a larger amount as 1 TFT.

The amount withdrawn from TF Chain will be sent to your Stellar wallet.

Example: ![swap_to_stellar](swap_to_stellar.png)
Example: ![swap\_to\_stellar](swap_to_stellar.png)

## Deeper look at how the TFChain Bridge works

### STELLAR -> TFCHAIN (Lock-and-Mint flow)

In this section, we look into the details of transferring TFT from a Stellar Account to a TFChain Account.

1. A transaction is received on the bridge Stellar account (aka. vault) and noticed by bridge validators (deamons).

2. Each time such transaction event is received by a bridge validator it undergoes some validation. If it fails, a refund is issued (sent back to the stellar source account). Here we assume that the validation has passed, but we will examine the refund flow in the next section.

3. The first bridge validator reporting the transaction will propose a mint by calling `propose_or_vote_mint_transaction()` extrinsic on the TFTBridgeModule in TFChain. This extrinsic inserts a new `MintTransaction` in `MintTransactions` storage that includes the `amount`, `target`, `block`, `votes`, and emits a `MintTransactionProposed` event. The mint is considered processed by the bridge side at this point.

4. Other bridge validators that report the transaction later will only add their votes for that proposal by calling same TFChain extrinsic. Since the `MintTransaction` already exists in `MintTransactions` storage, the extrinsic will increment the `votes` count for the specified `MintTransaction` and emit `MintTransactionVoted` event.

5. From the TFChain side, if the majority (more than the half) of bridge validators agree on the transaction, tokens are minted to the target address. This check happens every time the `propose_or_vote_mint_transaction()` extrinsic is executed by validator call. Then, the transaction is removed from bridge pallet `MintTransactions` storage and added to `ExecutedMintTransactions`. Finally, a `MintCompleted` event is emitted.

#### Overview of the TFChain Minting events

1. `tftBridgeModule.MintTransactionProposed`: A bridge validator proposed a mint transaction after being the first to report a stellar deposit.
2. `tftBridgeModule.MintTransactionVoted`: Other bridge validators reported same stellar deposit and voted for the mint proposal.
3. `tftBridgeModule.MintCompleted`: Enough bridge validator votes was collected and the tokens was successfully minted to the target address.

#### When a Refund-on-Stellar occurs?

A refund on Stellar occurs when one of the following conditions is met:

* The deposited amount is lower than the deposit fee.
* The memo message is empty.
* The transaction contains more than one payment.
* The memo is not formatted correctly.
* The grid type is not supported (not one of grid, farm, node, or entity) or not found.

### STELLAR -> TFCHAIN (Refund-on-Stellar flow)

In this section, we look into the details of what happens when the a Stellar deposit can not be processed due to a validation problem.

1. A transaction is received on the bridge Stellar account (aka. vault) and noticed by bridge validators (deamons).

2. Each time such transaction event is received by a bridge validator it undergoes some validation. Here, we assume that the validation has failed because of one of the violations mentioned in the previous section so a refund flow is initiated.

3. The first bridge validator reporting a violation will initiate the refund by calling TFTBridgeModule `create_refund_transaction_or_add_sig()` extrinsic to propose a `RefundTransaction`, to store the details in `RefundTransactions` storage map alongside with its signature and to emit `RefundTransactionsignatureAdded` and `RefundTransactionCreated` events.

4. Other bridge validators that report the transaction later also provides their signature for that refund transaction proposal by calling same extrinsic.

5. If the majority (more than the half) of bridge validators provided their signature for a refund transaction, a `RefundTransactionReady` event is emitted as well. This check happens every time the `create_refund_transaction_or_add_sig()` extrinsic is executed by validator call.

6. The first bridge validator reporting the `RefundTransactionReady` event will handle it and query TFChain storage for the `RefundTransaction` details and the validators’ signatures. It will create a multi-signatures Stellar transaction with a [MEMO](https://developers.stellar.org/docs/encyclopedia/memos) of `RETURN` type containing the hash of the refunded transaction and submit it to Stellar network. If submitted successfully, it will call `set_refund_transaction_executed()` extrinsic (which removes the `RefundTransaction` from the `RefundTransactions` storage and adds it to `ExecutedRefundTransactions`) then emit `RefundTransactionProcessed` event.

#### Overview of the TFChain Refund events

1. `tftBridgeModule.RefundTransactionCreated`: A bridge validator proposed a Refund-on-Stellar transaction after being the first to report a stellar deposit with invalid or missing cross-chain transfer information.
2. `tftBridgeModule.RefundTransactionsignatureAdded`: Other bridge validators reported same stellar deposit and provided signature for the refund proposal.
3. `tftBridgeModule.RefundTransactionReady`: Enough validators signatures were collected and stored so from now it is possible to submit the proposed stellar refund transaction.
4. `tftBridgeModule.RefundTransactionProcessed`: A bridge validator called `set_refund_transaction_executed()` extrinsic with a proof that the proposed stellar refund transaction was executed successfully on stellar network.

### TFCHAIN -> STELLAR (Burn-and-Withdraw flow)

Now, we look into the details of transferring TFT from a TFChain account to a Stellar account. On TFChain network we burn TFT and on Stellar network we withdraw TFT from TFChain.

1. To withdraw your asset back to Stellar, the TFTBridgeModule's `swap_to_stellar()` extrinsic in TFChain must be called with an amount to burn (on the TFChain side) and a Stellar account ID to receive the equivalent TFT amount (on the Stellar network side).

2. The call validates the target Stellar account ID and ensures that you have enough balance in the source account. If so, it burns the amount and transfer fees to feeAccount, increments the `BurnTransactionId` in the TFTBridgeModule storage, stores data about the transaction with empty signatures placeholder, adds it to `BurnTransactions` with the `burnId` as key, and emits `BurnTransactionCreated` event. This event contains `burn_id`, `source` account, `target` Stellar address, and burn `amount`.

3. The bridge validators are listening to this event. They extract the `burnId` and other transaction parameters, validate the Stellar address (tokens could be refunded/minted back on TFChain at this step if validation failed), then construct signed stellar transaction and extract the signature (note, the transaction can not be submitted yet to stellar network). They then call `propose_burn_transaction_or_add_sig()` extrinsic which fills their signatures and the bridge account sequence number in the `BurnTransaction` in storage that matches specified `burnId`. When this call executed, the `BurnTransactionSignatureAdded` event is emitted.

4. If the majority (more than the half) of bridge validators provided their signature for the transaction, a `BurnTransactionReady` event is emitted as well. This check happens every time the `propose_burn_transaction_or_add_sig()` extrinsic is executed by validator call.

5. The bridge will handle the event and query TFChain storage for the `BurnTransaction` details and the validators’ signatures. It will create a multi-signatures Stellar transaction and submit it to Stellar network. If submitted successfully, it will call `set_burn_transaction_executed()` extrinsic (which removes the `BurnTransaction` from the `BurnTransactions` storage and adds it to `ExecutedBurnTransactions`) then emit `BurnTransactionProcessed` event.

#### Overview of the TFChain Burning events

1. `tftBridgeModule.BurnTransactionCreated`: A swap from TFChain to stellar was initiated by a call to `swap_to_stellar()` extrinsic.
2. `tftBridgeModule.BurnTransactionSignatureAdded`: A bridge validator handled BurnTransactionCreated TFChain event and submitted its signature for the proposed stellar transaction.
3. `tftBridgeModule.BurnTransactionReady`: Enough validators signatures were collected and stored so from now it is possible to submit the proposed stellar withdraw transaction.
4. `tftBridgeModule.BurnTransactionProcessed`: A bridge validator was the first to call `set_burn_transaction_executed()` extrinsic and the proposed stellar withdraw transaction was executed successfully on stellar network.

#### When a Refund-on-TFChain occurs?

A refund on TFChain is initiated when either of the following conditions is met:

* Account information cannot be retrieved from the Stellar network.
* The account has no trust line to TFT tokens or has a deleted one (TFT balance limit is `0`).

### TFChain Retry mechanism

We didn't mentioned yet a few TFChain event related to the flows discussed above, these events are:

* `tftBridgeModule.BurnTransactionExpired`: from TFCHAIN -> STELLAR burn flow, certain number of TFChain blocks passed without a `BurnTransaction` being noticed and signed by the majority of bridge validators.
* `tftBridgeModule.RefundTransactionExpired`: from STELLAR -> TFCHAIN refund flow, certain number of TFChain blocks passed without a `RefundTransaction` being noticed and signed by the majority of bridge validators.

These expired events are typically the result of an outage of one or more bridge validators. We will explain why.

TFChain has a retry mechanism built into its runtime that takes into account possible bridge validator outages. If a certain number of TFChain blocks pass without a `BurnTransaction` or `RefundTransaction` being noticed and signed by the majority of bridge validators, the stored transaction signatures are reset and a `BurnTransactionExpired` or `RefundTransactionExpired` event is emitted.

These events will continue to occur until the unavailable bridge validators come back online and handle the expired events as it gets re-emitted.
28 changes: 24 additions & 4 deletions bridge/docs/readme.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
# Development
# TFChain Bridge

TFChain bridge is a Chain-To-Chain bridge which mainly designed to support the movement of assets between two blockchains, TFChain and Stellar.
It is composed as a daemon that runs in the background scanning a Stellar vault address for deposits and TFChain Events for withdrawals and executes upon them. This allows cross-chain transfers between Stellar <> TFChain.

## what is a blockchain bridge?

Blockchain bridges connect two different blockchains, similar to how real-world bridges connect two different locations. Without a bridge, blockchains are siloed environments that cannot communicate with each other because each network has its own set of rules, governance mechanisms, native assets, and data that are incompatible with the other blockchains. However, with a bridge between two blockchains, it becomes possible to transfer crypto-assets and arbitrary data between them. Bridges are key for interoperability in the crypto ecosystem and are necessary to make different blockchain networks compatible with each other.

## Cross-Chain Mechanism

Bridges can be categorized by a number of characteristics. These include how they transfer information across chains which consider the most important factor.

Our bridge between Stellar TFT and TFChain TFT use a mechanism known as “locking” or “burning,” followed by either minting or withdrawing, respectively. let's describe how the mechanism works by using an example.
- the user begins by depositing the Stellar TFT version into a designated stellar address owned by the bridge and specifying the recipient on TFChain. This step is referred to as “locking.”.
- the bridge initiate a flow to “mints” or issues a version of the deposited asset on TFChain and credits it to the recipient account.
- When the user wants to move back to Stellar TFT, the TFChain token is simply “burned.” This allows the underlying asset on Stellar to be redeemed and sent to the specified recipient address.

## Development

In this document we will explain how the bridge works and how you can setup a local instance to develop against.
The local instance will consist of a connection between a tfchain that runs in development mode and Stellar Testnet.

See [architecture](./architecture.md) for more information on how the bridge works.

## Development setup
## Setup

### Development setup

Refer to [development](./development.md) for more information on how to setup a development instance.

## Production setup
### Production setup

Refer to [production](./production.md) for more information on how to setup a production instance.

## Bridging
### Bridging

When you have setup the bridge in either development or production mode you can start bridging.

Expand Down
2 changes: 1 addition & 1 deletion bridge/docs/single_node.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ First identify the bridge master address you generated above, in this example th
Now construct a memo message indicating which twin you will deposit to: "twin_TWINID" (you should have created a twin in the above steps).

```sh
./stellar-utils transfer 50 "twin_1" GAYJSBPBQ3J32CZZ72OM3GZP646KSVD3V5QB3WBJSSGPYHYS5MZSS4Z6 --secret SDGRCA63GSP4MSASFAWX5FORTS6ATQMK63YL6ZMF7YIFEJVBTLJDJA3M
./stellar-utils transfer GAYJSBPBQ3J32CZZ72OM3GZP646KSVD3V5QB3WBJSSGPYHYS5MZSS4Z6 50 "twin_1" --secret SDGRCA63GSP4MSASFAWX5FORTS6ATQMK63YL6ZMF7YIFEJVBTLJDJA3M
```

Now you should have received the tokens minus the depositfee on your account on tfchain (the default depositfee is 10 TFT).

0 comments on commit 38ea787

Please sign in to comment.