# Cross-Chain Bridge Assessment Process

**URL:** <https://gov.uniswap.org/t/cross-chain-bridge-assessment-process/20148>\
**Category:** Uncategorized\
**Created:** [January 28, 2023, 3:09pm UTC](https://gov.uniswap.org/t/cross-chain-bridge-assessment-process/20148 "2023-01-28T15:09:14Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![modong](https://sea2.discourse-cdn.com/flex016/user_avatar/gov.uniswap.org/modong/32/6942_2.png) [@modong](https://gov.uniswap.org/u/modong)\
**Post date:** [January 31, 2023, 3:10pm UTC](https://gov.uniswap.org/t/cross-chain-bridge-assessment-process/20148/4 "2023-01-31T15:10:44Z")

</div>

# A Multi-bridge Implementation for Uniswap Governance is Now Available

This post includes the implementation of **a multi-bridge Uniswap governance solution** that is **vendor-lock-in-free** for Uniswap community to consider.

This solution is strictly better than choosing a single bridge in terms of security and availability. In addition, it also retains the strongest bargaining power in the hands of Uniswap community to always receive the best services. [See this for more context.](https://gov.uniswap.org/t/rfc-update-deploy-uniswap-v3-1-0-3-0-05-0-01-on-bnb-chain-binance/19734/40)

The implementation combines both Celer and Wormhole and is open-sourced here  
[https://github.com/celer-network/sgn-v2-contracts/blob/multibridge/contracts/message/apps/multibridge/](https://github.com/celer-network/sgn-v2-contracts/blob/multibridge/contracts/message/apps/multibridge/)

All other bridges/cross-chain solutions such as LayerZero can be added easily via adapters.

A testnet deployment is done.

Setup:

- Source Chain: Avalanche Fuji testnet
- Destination Chain: BSC testnet

The reason we did not use Ethereum Goeril is that there is no available generic relayer from @Wormhole on Goeril and Wormhole team has not responded to us in assisting things.

- Cross-chain solutions used: Celer, Wormhole
- Contract addresses:  
– MultiBridgeSender Fuji [0x5a5F095183241f4B23a7Aa7f8949fd02D06CaeCf](https://testnet.snowtrace.io/address/0x5a5F095183241f4B23a7Aa7f8949fd02D06CaeCf)  
– CelerSenderAdapter fuji [0x243b40e96c6bF21511E53d85c86F6Ec982f9a879](https://testnet.snowtrace.io/address/0x243b40e96c6bF21511E53d85c86F6Ec982f9a879)  
– WormholeSenderAdapter fuji  
[0x0cb93b5c42437FE78b3697740D15b46707f97361](https://testnet.snowtrace.io/address/0x0cb93b5c42437FE78b3697740D15b46707f97361)  
– MultiBridgeReceiver bsctest [0x207fF5290Bb518D963CF0a62B371B5B2dB6943A2](https://testnet.bscscan.com/address/0x207fF5290Bb518D963CF0a62B371B5B2dB6943A2)  
– CelerReceiverAdapter bsctest [0x37D2F4DCb5986ce2639bd66B022dcb9e3879156c](https://testnet.bscscan.com/address/0x37D2F4DCb5986ce2639bd66B022dcb9e3879156c)  
– WormholeReceiverAdapter bsctest  
[0xa5711D74780527484Be167bA3052eD3700d52B1D](https://testnet.bscscan.com/address/0xa5711D74780527484Be167bA3052eD3700d52B1D)  
– UniswapV3Factory bsctest  
[0x0bEC2a9E08658eAA15935C25cfF953caB2934C85](https://testnet.bscscan.com/address/0x0bec2a9e08658eaa15935c25cff953cab2934c85)

Test results:

- Source chain transaction: [https://testnet.snowtrace.io/tx/0xa6f2b3af99773f6d03b5b31b37e95732366fbe6d25a5c2dc6358ab88860047a0](https://testnet.snowtrace.io/tx/0xa6f2b3af99773f6d03b5b31b37e95732366fbe6d25a5c2dc6358ab88860047a0)
- Destination Chain tx1: message from wormhole:  
[https://testnet.bscscan.com/tx/0x2db8178ce5130945fee24fc7da3d5273921234dd6fa10655f5baaea6f90cb2f5](https://testnet.bscscan.com/tx/0x2db8178ce5130945fee24fc7da3d5273921234dd6fa10655f5baaea6f90cb2f5)
- Destination Chain tx2: message from celer and execute the governance call:  
[https://testnet.bscscan.com/tx/0xfbb0680033a841cadf197cf6b85f5794f764f2edeb27192353edd3cf668987fe](https://testnet.bscscan.com/tx/0xfbb0680033a841cadf197cf6b85f5794f764f2edeb27192353edd3cf668987fe)

Now let’s get to the solution specification.

# Send Cross-Chain Messages through Multiple Bridges

This is a solution for cross-chain message passing without vendor lock-in and with enhanced security beyond any single bridge. A message with multiple copies are sent through different bridges to the destination chains, and will only be executed at the destination chain when the same message has been delivered by a quorum of different bridges.

The current solution are designed for messages being sent from one source chain to multiple destination chains. It also requires that there is only one permitted sender on the source chain. This would be the use case for Uniswap governance contract on Ethereum  
calling remote functions of contracts on other EVM chains.

## Workflow

### Send message on source chain

To send a message to execute a remote call on the destintion chain, sender on the source chain should call [`remoteCall()`](https://github.com/celer-network/sgn-v2-contracts/blob/261fe55b320393a1336156b5771867a36db43198/contracts/message/apps/multibridge/MultiBridgeSender.sol#L28-L40) of `MultiBridgeSender`, which invokes `sendMessage()` of every bridge sender apdater to send messages via different message bridges.

```auto
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Source chain │
│ │
│ ┌─────────────────┐ ┌───────────────────┐ │
│ ┌──►│ Bridge1 Adapter ├──►│ Bridge1 Contracts │ │
│ │ └─────────────────┘ └───────────────────┘ │
│ │ │
│ ┌────────┐remoteCall()┌───────────────────┐sendMessage()│ ┌─────────────────┐ ┌───────────────────┐ │
│ │ Caller ├───────────►│ MultiBridgeSender ├─────────────┼──►│ Bridge2 Adapter ├──►│ Bridge2 Contracts │ │
│ └────────┘ └───────────────────┘ │ └─────────────────┘ └───────────────────┘ │
│ │ │
│ │ ┌─────────────────┐ ┌───────────────────┐ │
│ └──►│ Bridge3 Adapter ├──►│ Bridge3 Contracts │ │
│ └─────────────────┘ └───────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────┘

```

### Receive message on destination chain

On the destination chain, MultiBridgeReceiver receives messages from every bridge receiver adapter. Each receiver adapter gets encoded message data from its bridge contracts, and then decode the message and call `receiveMessage()` of `MultiBrideReceiver`.

`MultiBridgeReceiver` maintains a map from bridge adapter address to its power. Only adapter with non-zero power has access to `receiveMessage()` function. **If the accumulated power of a message has reached the a threshold, which means enough number of different bridges have delivered a same message, the message will be executed** by the `MultiBrideReceiver` contract.

The message execution will invoke a function call according to the message content, which will either call functions of other contracts, or call the param adjustment functions of the `MultiBridgeReceiver` itself. Note that the only legit message sender is the trusted dApp contract on the source chain, which means only that single dApp contract has the ability to execute functions calls through the `MultiBridgeReceiver` contracts on different other chains.

```auto
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Destination chain │
│ │
│ ┌───────────────────┐ ┌─────────────────┐ │
│ │ Bridge1 Contracts ├──►│ Bridge1 Adapter ├──┐ │
│ └───────────────────┘ └─────────────────┘ │ │
│ │ │
│ ┌───────────────────┐ ┌─────────────────┐ │receiveMessage()┌─────────────────────┐ call() ┌──────────┐ │
│ │ Bridge1 Contracts ├──►│ Bridge2 Adapter ├──┼───────────────►│ MultiBridgeReceiver ├────────►│ Receiver │ │
│ └───────────────────┘ └─────────────────┘ │ └─────────────────────┘ └──────────┘ │
│ │ │
│ ┌───────────────────┐ ┌─────────────────┐ │ │
│ │ Bridge2 Contracts ├──►│ Bridge3 Adapter ├──┘ │
│ └───────────────────┘ └─────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

```

### Add new bridge and update threshold

Below are steps to add a new bridge (e.g. Bridge4) by the dApp community.

1. Bridge4 provider should implement and deploy Bridge4 adapters on source chain and all destination chains. The adapter contracts should meet the following requirements.
  - On the source chain, the sender adapter should only accept `sendMessage()` call from `MultiBridgeSender`.
  - On the destination chain, the receiver adapter should only accept messages sent from the Bridge4 sender adapter on the source chain, and then call `receiveMessage()` of `MultiBridgeReceiver` for each valid message.
  - Renounce any ownership or special roles of the adapter contracts after inital parameter setup.

2. Bridge4 provider deploy and open source the adapter contracts. dApp community should review the code and check if the requirements above are met.
3. dApp contract (`Caller`) on the source chain adds the new Bridge4 sender adapter to `MultiBridgeSender` on the source chain by calling the `addSenderAdapters()` function of `MultiBridgeSender`.
4. dApp contract (`Caller`) on the source chain adds the new Bridge4 receiver adapter to `MultiBridgeReceiver` on the destination chain by calling the [`remoteCall()`](https://github.com/celer-network/sgn-v2-contracts/blob/261fe55b320393a1336156b5771867a36db43198/contracts/message/apps/multibridge/MultiBridgeSender.sol#L28-L40) function of `MultiBridgeSender`, with arguments to call [`updateReceiverAdapter()`](https://github.com/celer-network/sgn-v2-contracts/blob/60706f4eb6a179a9518bccf8408299f42a44f988/contracts/message/apps/multibridge/MultiBridgeReceiver.sol#L78-L88) of the `MultiBridgeReceiver` on the destination chain.

Updating quorum threshold is similar to configure a new bridge receiver adapter on destination chain. It requires a `remoteCall()` from the source chain `Caller` with calldata calling [`updateQuorumThreshold()`](https://github.com/celer-network/sgn-v2-contracts/blob/60706f4eb6a179a9518bccf8408299f42a44f988/contracts/message/apps/multibridge/MultiBridgeReceiver.sol#L90-L99) of the `MultiBridgeReceiver` on the destination chain.

## Example

Use case: contract A on Goerli send message to contract B on BSC Testnet in order to call `enableFeeAmount()` for state change. Apply a 2-of-3 messages governance model with message bridge C, D and E.

### Deployment and initialization

- Deploy `MultiBridgeSender` on Goerli, set address of A as allowed [caller](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/MultiBridgeSender.sol#L12).
- Deploy `MultiBridgeReceiver` on BSC Testnet.
- Each message bridge provider prepare their own `SenderAdapter` and `ReceiverAdapter`, named with a prefix of their bridge name. Take preparation of `CSenderAdapter` and `CReceiverAdapter` as an example.
  - Deploy `CSenderAdapter` on Goerli, set address of `MultiBridgeSender` as [multiBridgeSender](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/adapters/CelerSenderAdapter.sol#L12).
  - Deploy `CReceiverAdapter` on BSC Testnet, set address of `MultiBridgeReceiver` as [multiBridgeReceiver](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/adapters/CelerReceiverAdapter.sol#L34).
  - Call [updateReceiverAdapter()](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/adapters/CelerSenderAdapter.sol#L42) of `CSenderAdapter`, set address of `CReceiverAdapter` on BSC Testnet(chain id 97) as a valid ReceiverAdapter.
  - Call [updateSenderAdapter()](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/adapters/CelerReceiverAdapter.sol#L60) of `CReceiverAdapter`, set address of `CSenderAdapter` on Goerli(chain id 5) as a valid SenderAdapter.
  - Transfer ownership of `CSenderAdapter` and `CReceiverAdapter` to address(0).

- Once all message bridges are ready, somehow let contract A call [addSenderAdapters()](https://github.com/celer-network/sgn-v2-contracts/blob/1cbc2a3038463e7569b1a459c3519c7fcfeaaa4a/contracts/message/apps/multibridge/MultiBridgeSender.sol#L74) of `MultiBridgeSender` with an address array of `CSenderAdapter`, `DSenderAdapter` and `ESenderAdapter`.
- Call `initialize()` of `MultiBridgeReceiver`, with an address array of `CReceiverAdapter`, `DReceiverAdapter` and `EReceiverAdapter`, and power threshold 2.

### Sending your message

Prepare a calldata for contract B for calling `enableFeeAmount()`, then somehow let contract A call `remoteCall()` of `MultiBridgeSender` with `_dstChainId = 97`, `_target = <address of contract B>` and `_callData = <calldata you prepared>`.

### Result

Imagine that the messages sent via C, D and E received by `MultiBridgeReceiver` on BSC Testnet in an order of `1.C 2.D 3.E`. During receiving message sent via D, accumulated power reaches power threshold 2, which result in message execution(the calldata will be sent to contract B).

## Notes to the community

We are more than happy to answer any questions, help with tests, collaborate with similar-minded builders like @AlexSmirnov, iterate based on feedbacks and provide audits from community selected firms.

Although Celer, being a 2018-vintage project, does not have the backing of large UNI-holding investors at this moment, we do trust the integrity and intelligence of all the Uniswap delegates to choose this positive-sum path that ensures the highest level of security and service quality for Uniswap’s multi-blockchain expansion.

---

_[View the full topic](https://gov.uniswap.org/t/cross-chain-bridge-assessment-process/20148)._
