# Bridging Lucid Assets

## Introduction

To bridge tokens from **Chain A** to **Chain B**, an **Asset Controller** contract must be deployed on **both chains**.

To successfully bridge tokens from a controller on a source chain, ensure that:

* The selected **bridge adapter** is whitelisted by an admin.
* The adapter has sufficient **mint/burn limits** (unless bridging without limits).

The following sections describe how to **manually bridge tokens** by interacting directly with the smart contracts. This is intended for **advanced users**. It is recommended to use the **Lucid App** to bridge tokens or to construct/export transactions for execution via **Safe**, **Snapshot’s oSnap module**, or a **Governor proposal**.

## Bridging Tokens

To bridge Lucid assets,  you interact directly with the Lucid Wrapper contract (address and deployed chains can be [viewed here](https://docs.lucidlabs.fi/developer-reference/deployed-contracts/controller-contracts)), which serves as the entry point to bridge Lucid assets across any chain. It also supports EIP-2612 (aka ERC20Permit) for compatible assets, so the erc20 approve transaction can be skipped. The following functions are available on the Lucid Wrapper contract:

{% file src="<https://1245019432-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWTLxE0cK05dkLTY4VPzs%2Fuploads%2FTCHV6fWVXNkrvQvfZeGs%2FlucidWrapper.abi.json?alt=media&token=c7f4bab6-2e54-400f-82c1-c36cea4dfd2d>" %}

## Single Bridge

Using a single bridge is the default way to bridge tokens. You can initiate a transfer by calling `transferTo`  on the Wrapper contract on the **source chain**:

### transferTo

* Burns or locks tokens (depending on the configuration) on the source chain
* Sends a mint message to the destination chain via the selected **bridge adapter**
* `msg.value` must contain the **bridge adapter fee**
* The token **allowance** must be approved prior to calling this function

```solidity
function transferTo(DepositInput calldata input, address adapter, bytes calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type         | Description                                                                                                   |
| --------------- | ------------ | ------------------------------------------------------------------------------------------------------------- |
| `input`         | DepositInput | A [DepositInput](#depositinput)  struct                                                                       |
| `adapter`       | address      | The address of the bridge adapter to use                                                                      |
| `bridgeOptions` | bytes        | Additional params to be used by the adapter. Refer to the documentation of the specific adapter you are using |
| `data`          | bytes        | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.    |

If the selected bridge adapter is not whitelisted, or if it does not have sufficient burn limits, the transaction will revert. Any account holding the token managed by the Asset Controller can initiate a transfer.

#### Events emitted

The following events are emitted after a transfer has been sent:

From the Lucid Wrapper contract:

```solidity
event TransferSent( address indexed sender, address indexed controller, bool resent, bool multi, uint256 grossAmount, uint256 netAmount, bytes data );
```

The `data` bytes array is emitted unchanged from the input parameters.

From the Asset Controller contract:

```solidity
event TransferCreated(bytes32 indexed transferId, uint256 indexed destChainId, uint256 threshold, address indexed sender, address recipient, uint256 amount, bool unwrap);
```

The `transferId` can be used to:

* Resend the transfer using another adapter
* Track delivery status on the destination chain or the Lucid App

### transferToWPermit

This function works similar to `transferTo()` as outlined above, but it accepts an EIP-2612 signature to register the user's ERC20 approval, eliminating the need for a prior `approve()` transaction. If the signature is invalid, the transaction will revert.

Can only be used with tokens that implement EIP-2612. Check if the token you are bridging supports this functionality.

```solidity
function transferToWPermit( DepositInput calldata input, PermitData calldata permit, address bridgeAdapter, bytes calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type         | Description                                                                                                   |
| --------------- | ------------ | ------------------------------------------------------------------------------------------------------------- |
| `input`         | DepositInput | A [DepositInput](#depositinput)  struct                                                                       |
| `permit`        | PermitData   | A [PermitData](#permitdata) struct                                                                            |
| `bridgeAdapter` | address      | The address of the bridge adapter to use                                                                      |
| `bridgeOptions` | bytes        | Additional params to be used by the adapter. Refer to the documentation of the specific adapter you are using |
| `data`          | bytes        | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.    |

### resendTransfer

If a bridge fails to deliver a transfer to the destination chain, **anyone** can call `resendTransfer`, specifying the `transferId` and a different whitelisted adapter.

* No new tokens will be burned
* The original bridge message is resent using the new adapter
* The **burn amount** is deducted from the new adapter’s **burn limit**
* The function is **payable**, and `msg.value` must contain the new adapter’s fee

```solidity
function resendTransfer( address controller, bytes32 transferId, address adapter, bytes calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type    | Description                                                                                                                         |
| --------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `controller`    | address | The [controller](https://docs.lucidlabs.fi/developer-reference/deployed-contracts/controller-contracts) address of the asset to use |
| `transferId`    | bytes32 | The unique identifier of the message.                                                                                               |
| `adapter`       | address | The address of the bridge adapter.                                                                                                  |
| `bridgeOptions` | bytes   | Additional abi-encoded options that are passed to the bridge adapter, specific for the bridge adapter.                              |
| `data`          | bytes   | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.                          |

#### Events emitted

The following events are emitted after a transfer has been sent:

From the Lucid Wrapper contract:

```solidity
event TransferSent( address indexed sender, address indexed controller, bool resent, bool multi, uint256 grossAmount, uint256 netAmount, bytes data );
```

From the Asset Controller contract:

```solidity
event TransferResent(bytes32 indexed transferId);
```

{% hint style="info" %}
Lucid will not automatically relay transactions bridged via Polymer when the destination chain is Ethereum Mainnet. In these cases, the recipient must manually execute the transaction and cover the required gas fees via the Lucid App.
{% endhint %}

## Multiple Bridges (higher limits)

For transfers that exceed a single adapter’s limit, you can use multiple bridge adapters by calling the overloaded `transferTo()` function. This function:

* Burns tokens on the source chain
* Sends the mint message through multiple **whitelisted adapters**
* Requires the addresses of adapters that have been pre-approved **for with higher limits**
* `msg.value` must include any **multi-bridge fees**
* The token **allowance** must be set before calling this function.

To determine:

* The **minimum number of adapters** required for minting (if 0 is returned, then multiple bridges support is disabled):

```solidity
function minBridges() public view returns (uint256);
```

To determine whether a specific adapter is **approved for bridging with higher limits:**

```solidity
function multiBridgeAdapters(address adapter) public view returns (bool);
```

To get the current multi-bridge limits, call `bridges(0x0).`

### transferTo (multiple bridges)

To send a transfer, call the following function:

```solidity
function transferTo( DepositInput calldata input, address[] memory adapters, uint256[] memory fees, bytes[] calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type         | Description                                                                                                    |
| --------------- | ------------ | -------------------------------------------------------------------------------------------------------------- |
| `input`         | DepositInput | A [DepositInput](#depositinput)  struct                                                                        |
| `adapters`      | address\[]   | The addresses of the bridge adapter to use.                                                                    |
| `fees`          | uint256\[]   | The fees to be paid to the bridge adapters (in the same order as `adapters`).                                  |
| `bridgeOptions` | bytes\[]     | Additional params to be used by each adapter. Refer to the documentation of the specific adapter you are using |
| `data`          | bytes        | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.     |

A token allowance must be given before calling this function, which should include the multi-bridge fee, if any.

If the `bridgeAdapter` that was selected is not whitelisted, or the burn limits are not enough, then the transaction will revert.

#### Events emitted

The following events are emitted after a transfer has been sent:

From the Lucid Wrapper contract:

```solidity
event TransferSent( address indexed sender, address indexed controller, bool resent, bool multi, uint256 grossAmount, uint256 netAmount, bytes data );
```

The `data` bytes array is emitted unchanged from the input parameters.

From the Asset Controller contract:

```solidity
event TransferCreated(bytes32 indexed transferId, uint256 indexed destChainId, uint256 threshold, address indexed sender, address recipient, uint256 amount, bool unwrap);
```

The `transferId` can be used to:

* Resend the transfer using another adapter
* Track delivery status on the destination chain or the Lucid App

### transferToWPermit (multiple bridges)

This function works similar to `transferTo()` as outlined above, but it accepts an EIP-2612 signature to register the user's ERC20 approval, eliminating the need for a prior `approve()` transaction. If the signature is invalid, the transaction will revert.

Can only be used with tokens that implement EIP-2612. Check if the token you are bridging supports this functionality.

```solidity
function transferToWPermit( DepositInput calldata input, PermitData calldata permit, address[] memory adapters, uint256[] memory fees, bytes[] calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type         | Description                                                                                                    |
| --------------- | ------------ | -------------------------------------------------------------------------------------------------------------- |
| `input`         | DepositInput | A [DepositInput](#depositinput)  struct                                                                        |
| `permit`        | PermitData   | A [PermitData](#permitdata) struct                                                                             |
| `adapters`      | address\[]   | The addresses of the bridge adapter to use.                                                                    |
| `fees`          | uint256\[]   | The fees to be paid to the bridge adapters (in the same order as `adapters`).                                  |
| `bridgeOptions` | bytes\[]     | Additional params to be used by each adapter. Refer to the documentation of the specific adapter you are using |
| `data`          | bytes        | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.     |

#### Events emitted

The following events are emitted after a transfer has been sent:

From the Lucid Wrapper contract:

```solidity
event TransferSent( address indexed sender, address indexed controller, bool resent, bool multi, uint256 grossAmount, uint256 netAmount, bytes data );
```

The `data` bytes array is emitted unchanged from the input parameters.

From the Asset Controller contract:

```solidity
event TransferCreated(bytes32 indexed transferId, uint256 indexed destChainId, uint256 threshold, address indexed sender, address recipient, uint256 amount, bool unwrap);
```

The `transferId` can be used to:

* Resend the transfer using another adapter
* Track delivery status on the destination chain or the Lucid App

### resendTransfer (multiple bridges)

If delivery fails in a multi-bridge setup, the transfer can be resent using another whitelisted adapter by calling `resendTransfer()`.

* Works similarly to the single-bridge  `resendTransfer`  transfer
* No additional tokens are burned
* The message is simply resent using the new adapter

```solidity
function resendTransfer( address controller, bytes32 transferId, address[] calldata adapters, uint256[] calldata fees, bytes[] calldata bridgeOptions, bytes calldata data ) external payable
```

| Name            | Type       | Description                                                                                                                         |
| --------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `controller`    | address    | The [controller](https://docs.lucidlabs.fi/developer-reference/deployed-contracts/controller-contracts) address of the asset to use |
| `transferId`    | bytes32    | The unique identifier of the message.                                                                                               |
| `adapters`      | address\[] | The addresses of the bridge adapters.                                                                                               |
| `fees`          | uint256\[] | The fees to be paid to the bridge adapters  (in the same order as `adapters`).                                                      |
| `bridgeOptions` | bytes\[]   | Additional params to be used by each adapter. Refer to the documentation of the specific adapter you are using                      |
| `data`          | bytes      | An empty `bytes` array, or optionally a `bytes32` identifier (ABI-encoded) that will be emitted unchanged.                          |

#### Events emitted

The following events are emitted after a transfer has been sent:

From the Lucid Wrapper contract:

```solidity
event TransferSent( address indexed sender, address indexed controller, bool resent, bool multi, uint256 grossAmount, uint256 netAmount, bytes data );
```

From the Asset Controller contract:

```solidity
event TransferResent(bytes32 indexed transferId);
```

## Structs

#### DepositInput

```solidity
struct DepositInput {
    address controller; // address of the asset controller
    address recipient;
    uint256 amount;
    bool unwrap; // default to false
    uint256 destChainId;
}
```

{% hint style="info" %}
For a list of the available asset controller addresses, [check out this page](https://docs.lucidlabs.fi/developer-reference/deployed-contracts/controller-contracts).
{% endhint %}

#### PermitData

```solidity
struct PermitData {
    uint256 deadline;
    uint8 v;
    bytes32 r;
    bytes32 s;
}
```

## Fees

Before bridging assets, you should first estimate the fees. To do this, call the corresponding function on the Lucid Wrapper contract on the source chain, providing the controller address, the destination chain ID, and the amount to be bridged. The function will return both the estimated fee and the net amount you will receive on the destination chain.

Note that some transfers do not incur a fee, in which case you will receive the full amount.

```solidity
function quote(address controller, uint256 destChainId, uint256 amount) external view returns (uint256 fee, uint256 net)
```

## Token Minting

Once the message is delivered to the **destination Asset Controller** by the bridge adapters, the transfer must be **executed**.

Lucid will automatically execute the transfer once it becomes eligible. However, anyone can manually execute it by calling the following function on the asset controller on the destination chain, passing the transfer ID:

```solidity
function execute(bytes32 messageId) public;
```

This function can be called by any account.

{% hint style="info" %}
Lucid will not automatically execute transactions bridged via Polymer when the destination chain is Ethereum Mainnet. In these cases, the recipient must manually execute the transaction and cover the required gas fees—either by calling the function directly or using the Lucid App.
{% endhint %}
