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

SRC-10; Native Bridge Standard #45

Merged
merged 15 commits into from
Jan 11, 2024
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ If you don't find what you're looking for, feel free to create an issue and prop
- [SRC-5; Ownership Standard](./standards/src_5/) is used to restrict function calls to admin users in contracts.
- [SRC-7; Arbitrary Asset Metadata Standard](./standards/src_7/) is used to store metadata for [Native Assets](https://docs.fuel.network/docs/sway/blockchain-development/native_assets).
- [SRC-9; Metadata Keys Standard](./standards/src_9/) is used to store standardized metadata keys for [Native Assets](https://fuellabs.github.io/sway/v0.44.0/book/blockchain-development/native_assets.html) in combination with the SRC-7 standard.
- [SRC-10; Native Bridge Standard](./standards/src_10/) defines the standard API for the Native Bridge between the Fuel Chain and the canonical base chain.

## Using a standard

Expand Down
2 changes: 1 addition & 1 deletion standards/Forc.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["src_3", "src_5", "src_6", "src_7", "src_20"]
members = ["src_3", "src_5", "src_6", "src_7", "src_10", "src_20"]
Binary file added standards/src_10/.docs/src-10-logo-dark-theme.png
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.
5 changes: 5 additions & 0 deletions standards/src_10/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "src_10.sw"
license = "Apache-2.0"
name = "src_10"
123 changes: 123 additions & 0 deletions standards/src_10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset=".docs/src-10-logo-dark-theme.png">
<img alt="SRC-10 logo" width="400px" src=".docs/src-10-logo-light-theme.png">
</picture>
</p>

# Abstract

The following standard allows for the implementation of a standard API for Native Bridges using the Sway Language. The standardized design has the bridge contract send a message to the origin chain to register which token it accepts to prevent a loss of funds.

# Motivation

A standard interface for bridges intends to provide a safe and efficient bridge between the settlement or canonical chain and the Fuel Network.

# Prior Art

The standard is centered on Fuel’s [Bridge Architecture](https://github.com/FuelLabs/fuel-bridge/blob/main/docs/ARCHITECTURE.md). Fuel's bridge system is built on a message protocol that allows to send (and receive) messages between entities located in two different blockchains.

The following standard takes reference from the [FungibleBridge](https://github.com/FuelLabs/fuel-bridge/blob/3971081850e7961d9b649edda4cad8a848ee248e/packages/fungible-token/bridge-fungible-token/src/interface.sw#L22) ABI defined in the fuel-bridge repository.

# Specification

The following functions MUST be implemented to follow the SRC-10; Native Bridge Standard:

## Required Functions

### - `fn register_bridge(token_address: b256, gateway_contract: b256)`

The `register_bridge()` function compiles a message to be sent back to the canonical chain. The `gateway_contract` contract on the canonical chain receives the `token_address` token in the message such that when assets are deposited they are reported to prevent loss of funds.

> **NOTE:*** Trying to deposit tokens to a contract ID that does not exist or does not implement the Fuel Messaging Portal would mean permanent loss of funds.
bitzoic marked this conversation as resolved.
Show resolved Hide resolved

- This function MUST send a message on the canonical chain to the `gateway_contract` contract, registering the specified `token_address`.

### - `fn process_message(message_index: u64)`

The `process_message()` function accepts incoming deposit messages from the canonical chain and issues the corresponding bridged asset.

- This function MUST parse a message at the given `message_index` index.
- This function SHALL mint a token that follows the [SRC-8; Bridged Asset Standard](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_8).
- This function SHALL issue a refund if there is an error in the bridging process.

### - `fn withdraw(to_address: b256, sub_id: SubId, gateway_contract: b256)`

The `withdraw()` function accepts and burns a bridged asset and sends a message to the `gateway_contract` contract on the canonical chain to release the originally deposited token to the `to_address` address.

- This function SHALL send a message to the `gateway_contract` contract to release the bridged tokens to the `to_address` address on the canonical chain.
- This function MUST ensure the `sha256(contract_id(), sub_id)` matches the asset's `AssetId` sent in the transaction.
- This function SHALL burn all tokens sent in the transaction.

### - `fn claim_refund(to_address: b256, token_address: b256, token_id: Option<b256>, gateway_contract: b256)`

The `claim_refund()` function is called if something goes wrong in the bridging process and an error occurs. It sends a message to the `gateway_contract` contract on the canonical chain to release the `token_address` token with token id `token_id` to the `to_address` address.

- This function SHALL send a message to the `gateway_contract` contract to release the `token_address` token with id `token_id` to the `to_address` address on the canonical chain.
- This function MUST ensure a refund was issued.

## Required Data Types

### `MessageData`

The following describes a struct that encapsulates various message metadata to a single type. There MUST be the following fields in the `MessageData` struct:

#### - amount: `u256`

The `amount` field MUST represent the number of tokens.

#### - from: `b256`

The `from` field MUST represent the bridging user’s address on the canonical chain.

#### - len: `u16`

The `len` field MUST represent the number of the deposit messages to discern between deposits that must be forwarded to an EOA vs deposits that must be forwarded to a contract.

#### - to: `Identity`

The `to` field MUST represent the bridging target destination `Address` or `ContractId` on the Fuel Chain.

#### - token_address: `b256`

The `token_address` field MUST represent the bridged token's address on the canonical chain.

#### - token_id: `Option<b256>`

The `token_id` field MUST represent the token's ID on the canonical chain. MUST be `None` if this is a fungible token and no token ID exists.

### Example

```sway
struct MessageData {
amount: b256,
from: b256,
len: u16,
to: Identity,
token_address: b256,
token_id: Option<b256>,
}
```

## Required Standards

Any contract that implements the SRC-10; Native Bridge Standard MUST implement the [SRC-8; Bridged Asset Standard](https://github.com/FuelLabs/sway-standards/tree/master/standards/src_8) for all bridged assets.

# Rationale

The SRC-10; Native Bridge Standard is designed to standardize the native bridge interface between all Fuel instances.

# Backwards Compatibility

This standard is compatible with the SRC-20 and SRC-8 standards.

# Example ABI

```sway
abi SRC10 {
fn register_bridge(token_address: b256, gateway_contract: b256);
fn process_message(message_index: u64);
fn withdraw(to_address: b256, sub_id: SubId, gateway_contract: b256);
fn claim_refund(to_address: b256, token_address: b256, token_id: Option<b256>, gateway_contract: b256);
}
```
114 changes: 114 additions & 0 deletions standards/src_10/src/src_10.sw
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
library;

/// Enscapsultes metadata sent between the canonical chain and Fuel.
struct MessageData {
/// The number of tokens.
amount: b256,
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
/// The user's address on the canonical chain.
from: b256,
/// The number of deposit messages.
len: u16,
/// The bridging target destination on the Fuel chain.
to: Identity,
/// The bridged token's address on the canonical chain.
token_address: b256,
/// The token's ID on the canonical chain.
token_id: Option<b256>,
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
}

abi SRC10 {
/// Compiles a message to be sent back to the canonical chain.
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Additional Information
///
/// * The `gateway` contract on the canonical chain receives the `token` ID in the message such that when assets are deposited they are reported to prevent loss of funds.
///
/// # Arguments
///
/// * `token_address`: [b256] - The token's address on the canonical chain.
/// * `gateway_contract`: [b256] - The contract that accepts deposits on the canonical chain.
///
/// # Examples
///
/// ```sway
/// use src10::SRC10;
///
/// fn foo(gateway_contract: b256, token_address: b256, bridge: ContractId) {
/// let bridge_abi = abi(SRC10, bridge.value);
/// bridge_abi.register_bridge(token_address, gateway_contract);
/// }
/// ```
#[storage(read, write)]
fn register_bridge(token_address: b256, gateway_contract: b256);

/// Accepts incoming deposit messages from the canonical chain and issues the corresponding bridged asset.
///
/// # Arguments
///
/// * `message_index`: [u64] - The index of the message to parse.
///
/// # Examples
///
/// ```sway
/// use src10::SRC10;
///
/// fn foo(message_index: u64, bridge: ContractId) {
/// let bridge_abi = abi(SRC10, bridge.value);
/// bridge_abi.process_message(message_index);
/// }
/// ```
#[storage(read, write)]
fn process_message(message_index: u64);

/// Accepts and burns a bridged asset and sends a messages to the canonical chain to release the original deposited token.
///
/// # Arguments
///
/// * `to_address`: [b256] - The address on the canonical chain to send the released tokens to.
/// * `sub_id`: [SubId] - The SubId of the asset sent in the transaction.
/// * `gateway_contract`: [b256] - The contract that holds the deposited tokens on the canonical chain.
///
/// # Examples
///
/// ```sway
/// use src10::SRC10;
///
/// fn foo(to_address: b256, asset_sub_id: SubId, gateway_contract: b256, bridge: ContractId, bridged_asset: AssetId) {
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
/// let bridge_abi = abi(SRC10, bridge.value);
/// bridge_abi {
/// gas: 10000,
/// coins: 100,
/// asset_id: bridged_asset,
/// }.withdraw(to_address, asset_sub_id, gateway_contract);
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
/// }
/// ```
#[storage(read, write)]
fn withdraw(to_address: b256, sub_id: SubId, gateway_contract: b256);

/// Returns a refund on the canonical chain if an error occurs while bridging.
///
/// # Arguments
///
/// * `to_address`: [b256] - The address on the canonical chain to send the refunded tokens to.
/// * `token_address`: [b256] - The token on the canonical chain to be refunded.
/// * `token_id`: [Option<b256>] - The token id of the token on the canonical chain to be refunded.
/// * `gateway_contract`: [b256] - The contract that holds the deposited tokens on the canonical chain.
///
/// # Examples
///
/// ```sway
/// use src10::SRC10;
///
/// fn foo(to_address: b256, token_address: b256, token_id: Option<b256>, gateway_contract: b256, bridge: ContractId) {
/// let bridge_abi = abi(SRC10, bridge.value);
/// bridge_abi.claim_refund(to_address, token_address, token_id, gateway_contract);
/// }
/// ```
#[storage(read, write)]
fn claim_refund(
to_address: b256,
token_address: b256,
token_id: Option<b256>,
gateway_contract: b256,
);
}
Loading