Skip to content

Trustless Multi EVM Bridge

武宮誠 edited this page Sep 21, 2022 · 1 revision

Trustless Ethereum bridge with BEEFY proofs

Ethereum light client

Ethereum light client is based on a merkle proofs of a DAG. Ethereum block considered as finalized after 30 confirmations

Substrate light client

To verify messages from substrate on Ethereum side we use light client based on BEEFY. Full validation of BEEFY commitment require to send at least 2/3 of validator signatures which is require a lot of gas on Ethereum side. Instead we use small randomized subset of signatures to verify BEEFY commitment.

Pallets

ethereum-light-client

Pallet used to validate and store Ethereum headers and for transaction receipts verification.

Relayer interact with this pallet via ‘import_header’ extrinsic

basic(incentivized)-inbound-channel

Pallet used to send messages from Ethereum. This pallet use ethereum-light-client pallet to verify receipt

Relayer interact with this pallet via ‘submit’ extrinsic

basic(incentivized)-outbound-channel

Pallet used by another pallets to send messages to Ethereum. Every 10 blocks creates commitment with queued messages. Messages is saved in offchain DB, commitment hash with network id and channel id added to digest.

dispatch

Pallet used by inbound channels to decode and dispatch calls

eth-app

Pallet used to handle native Ethereum token transfers

User interact with ‘burn’ extrinsic

erc20-app

Pallet used to handle ERC20 tokens transfers

This pallet interact with ERC20App.sol for sidechain ERC20 tokens and with SidechainApp for tokens owned by SORA

User interact with ‘burn’ extrinsic

migration-app

Pallet used to migrate from old Ethereum bridge.

leaf-provider

This pallet provides MMR leaf extra data with hash of the digest items used by bridge

Smart contracts

BeefyLightClient

Contract used to update MMR tree root and validators Merkle tree root

Relayer interact with newSignatureCommitment and completeSignatureCommitment functions

ValidatorRegistry

Used to functions to store and verify validators

Basic(Incentivized)InboundChannel

Used by relayer to submit commitments from Substrate. Verifies commitment using BeefyLightClient and dispatch calls to App contracts

Basic(Incentivized)OutboundChannel

Used by App contracts to send messages to Substrate. Works only with allowed contracts

EthApp

Handle native Ethereum token transfers

ERC20App

Handle common ERC20 tokens transfers

SidechainApp

Handle transfers with tokens owned by SORA

Sequence diagrams

Substrate to Ethereum message sequence

image

Ethereum to Substrate message sequence

image

References

Beefy Docs

Bridge Setup Guide

Snowbridge Docs

DAG Merkle Proof

Testnet Bridge Endpoints

Mordor network (chainId = 63) Link

Bridge contracts

  • BeefyLightClient: 0x93a668Afa9055235c27FE017bE510e3BeA68297E
  • Bitfield: 0xd6eC25735308cBC8370dd83Bbd14d069AbC61d24
  • ERC20App: 0x42d90437f0a0D9a97D71a909B740f4A4E7Ad783F
  • ETHApp: 0xf5Aa7f6E47d37133612a80432141C0EFDD4cd77C
  • InboundChannel: 0xa1BB118A2912D536E292EFeD93c7b70Ab4dc8f89
  • MerkleProof: 0xd960Da7cB929758B033ff25C02a9C071d0d08DC2
  • MigrationApp: 0xB95E6f19dB0AF089Af28cF76D40336147eA8CDC7
  • OutboundChannel: 0x3B7A22BCF40910C2e98CC6017E7390900B726b9a
  • ScaleCodec: 0x5ae337AC707E579f55cD8A9d35d522CE9064E7E1
  • SidechainApp: 0xFE0016cB30cEAe9bf0F0893A4A5917c74B9E58c7
  • SimplifiedMMRVerification: 0xe3c8D6F7503c95E1D757b01581aFBC9e8FbD3E60
  • ValidatorRegistry: 0x6c36Bf19801F10104C3e00ed0aDE9b5e75362552

Test tokens

FTT (First Test Token): 0x7b265A1D3Dd484CE4295144f65bCedCBfb35427b

STT(Second Test Token): 0x8332289B3fA4278FbCf737E1E7F5f4c8BE8f1052

Transfer Guide

This article explains how to make transfers in trustless ethereum bridge and watch on transfer progress

SORA → Ethereum

We have 2 bridge pallets for different asset kinds: ethApp for native Ethereum tokens and erc20App for ERC20 contracts(both native and external). To transfer tokens to Ethereum you need to call ethApp.burn(networkId, recipient, amount) or erc20App.burn(networkId, recipient, amount). Also now available evmBridgeProxy.burn(networkId, assetId, recipient, amount), which is support all asset kinds

networkId (U256) - chainId of selected Ethereum network

assetId (AssetId) - asset id

recipient (H160) - ethereum address

amount (Balance) - amount of tokens to transfer

Watching progress

Progress:

  1. Message in queue… After burn transaction is placed in queue (incentivizedOutboundChannel.messageQueues(networkId)) and MessageAccepted(nonce) event is created
  2. Update state on Ethereum side (1/2)… newSignatureCommitment function is called in BeefyLightClient on Ethereum side by relayer
  3. Update state on Ethereum side (2/2)… completeSignatureCommitment function is called in BeefyLightClient on Ethereum side by relayer
  4. Submitting messages… incentivizedInboundChannel.submit is called on Ethereum side by relayer

Ethereum → SORA

User need to call one of those functions to transfer tokens from Ethereum to SORA:

  1. ethApp.lock(bytes32 recipient) - should be used for native Ethereum tokens. Amount is passed as msg.value of transaction.
  2. erc20App.lock(address token, bytes32 recipient, uint256 amount) - should be used for external (created by another companies and users) ErC20 tokens.
  3. sidechainApp.lock(address token, bytes32 recipient, uint256 amount) - should be used for tokens which is native for SORA network (PSWAP, VAL, XOR, CERES)

recipient - address in SORA network

token - address of token to be transferred. Bridge contract should have enough allowance

amount - amount of tokens

Watching progress

As in previous bridge implementation we need to wait 30 blocks until transaction can be included in SORA network. ethereumLightClient.finalizedBlock storage contains latest block which is considered as finalized in Ethereum light client. When block with transfer transaction is finalized, relayer can import transaction with incentivizedInboundChannel.submit extrinsic and tokens will be minted/unlocked on SORA side.

Progress:

  1. Waiting for block finalization (1..30/30)…
  2. Waiting for transaction submit…

Get info about bridge

  1. token address by asset id

erc20App.tokenAddresses(networkId, assetId)

ethApp.addresses(networkId) - first value of tuple is token address

  1. asset id by token address

erc20App.assetsByAddresses(networkId, address)

ethApp.addresses(networkId) - second value of tuple is asset id

  1. transaction history by user

evmBridgeProxy.userTransactions(network_id, account_id) - get list of transaction hashes made by given user

evmBridgeProxy.transactions(network_id, hash) - get transaction details by hash

Links

Substrate extrinsics

erc20App.burn

ethApp.burn

Ethereum contract functions

erc20App.lock

ethApp.lock

sidechainApp.lock

Contracts ABI

https://github.com/sora-xor/sora2-network/tree/115bc84a4620a4a2be8a001fcf912d355728c9c2/relayer/ethereum-gen/src/bytes

How to run the Trustless EVM Bridge Relayer

Docker

docker run --rm -e "RUST_LOG=relayer=debug,info" --entrypoint relayer sora2/substrate:bridge --help

Build from source

cargo build --release --bin relayer ./target/release/relayer --help

Transfers

We will use BRIDGE STAGE environment endpoint as example

Transfer ETH(Mordor) tokens from Ethereum to Sora

relayer --ethereum-url https://www.ethercluster.com/mordor --substrate-url wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp:443 --ethereum-key your_ethereum_private_key bridge transfer-to-sora --asset-id 0x0200070000000000000000000000000000000000000000000000000000000000 --recipient your_account_id_in_sora_network --amount 1000000000000000000

Transfer ERC20 tokens from Ethereum to Sora

We will use FTT(First Test Token) for example. The relayer will automatically mint this token and approve transfer to bridge contract.

You can find asset_id for your token using polkadot.js/apps->developer->chain state->erc20App.assetsByAddresses

relayer --ethereum-url https://www.ethercluster.com/mordor --substrate-url wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp:443 --ethereum-key your_ethereum_private_key bridge transfer-to-sora --asset-id 0x005963f9e01c987ae213bca46603d8b569ebbf91d3c52ab59207d7e4dae87bff --recipient your_account_id_in_sora_network --amount 1000000000000000000

Transfer tokens from Sora to Ethereum

For example, send some XOR to Ethereum. Derive path for your account can be your account seed, for example

relayer --ethereum-url https://www.ethercluster.com/mordor --substrate-url wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp:443 --substrate-key derive_path_for_your_sora_account bridge transfer-to-sora --asset-id 0x0200000000000000000000000000000000000000000000000000000000000000 --recipient your_ethereum_address --amount 1000000000000000000

Relay messages

Ethereum → Sora

You’ll need at least 10GB of space on disk with path_for_dag_cache

relayer --ethereum-url https://www.ethercluster.com/mordor --substrate-url wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp:443 --substrate-key derive_path_for_your_sora_account bridge relay ethereum --base-path path_for_dag_cache

Sora → Ethereum

relayer --ethereum-url https://www.ethercluster.com/mordor --substrate-url wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp:443 --ethereum-key your_ethereum_private_key bridge relay substrate