-
Notifications
You must be signed in to change notification settings - Fork 23
Trustless Multi EVM Bridge
Ethereum light client is based on a merkle proofs of a DAG. Ethereum block considered as finalized after 30 confirmations
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.
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
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
Ethereum to Substrate message sequence
wss://ws.framenode-1.b1.stg1.sora2.soramitsu.co.jp
- rpc.framenode-1.b1.stg1.sora2.soramitsu.co.jp
- Polkadot.js/apps framenode-1
wss://ws.framenode-2.b1.stg1.sora2.soramitsu.co.jp
- rpc.framenode-2.b1.stg1.sora2.soramitsu.co.jp
- Polkadot.js/apps framenode-2
wss://ws.framenode-3.b1.stg1.sora2.soramitsu.co.jp
- rpc.framenode-3.b1.stg1.sora2.soramitsu.co.jp
- Polkadot.js/apps framenode-3
Mordor network (chainId = 63) Link
- BeefyLightClient:
0x93a668Afa9055235c27FE017bE510e3BeA68297E
- Bitfield:
0xd6eC25735308cBC8370dd83Bbd14d069AbC61d24
- ERC20App:
0x42d90437f0a0D9a97D71a909B740f4A4E7Ad783F
- ETHApp:
0xf5Aa7f6E47d37133612a80432141C0EFDD4cd77C
- InboundChannel:
0xa1BB118A2912D536E292EFeD93c7b70Ab4dc8f89
- MerkleProof:
0xd960Da7cB929758B033ff25C02a9C071d0d08DC2
- MigrationApp:
0xB95E6f19dB0AF089Af28cF76D40336147eA8CDC7
- OutboundChannel:
0x3B7A22BCF40910C2e98CC6017E7390900B726b9a
- ScaleCodec:
0x5ae337AC707E579f55cD8A9d35d522CE9064E7E1
- SidechainApp:
0xFE0016cB30cEAe9bf0F0893A4A5917c74B9E58c7
- SimplifiedMMRVerification:
0xe3c8D6F7503c95E1D757b01581aFBC9e8FbD3E60
- ValidatorRegistry:
0x6c36Bf19801F10104C3e00ed0aDE9b5e75362552
FTT (First Test Token): 0x7b265A1D3Dd484CE4295144f65bCedCBfb35427b
STT(Second Test Token): 0x8332289B3fA4278FbCf737E1E7F5f4c8BE8f1052
This article explains how to make transfers in trustless ethereum bridge and watch on transfer progress
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
Progress:
- Message in queue… After burn transaction is placed in queue (incentivizedOutboundChannel.messageQueues(networkId)) and MessageAccepted(nonce) event is created
- Update state on Ethereum side (1/2)… newSignatureCommitment function is called in BeefyLightClient on Ethereum side by relayer
- Update state on Ethereum side (2/2)… completeSignatureCommitment function is called in BeefyLightClient on Ethereum side by relayer
- Submitting messages… incentivizedInboundChannel.submit is called on Ethereum side by relayer
User need to call one of those functions to transfer tokens from Ethereum to SORA:
- ethApp.lock(bytes32 recipient) - should be used for native Ethereum tokens. Amount is passed as msg.value of transaction.
- erc20App.lock(address token, bytes32 recipient, uint256 amount) - should be used for external (created by another companies and users) ErC20 tokens.
- 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
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:
- Waiting for block finalization (1..30/30)…
- Waiting for transaction submit…
- token address by asset id
erc20App.tokenAddresses(networkId, assetId)
ethApp.addresses(networkId) - first value of tuple is token address
- asset id by token address
erc20App.assetsByAddresses(networkId, address)
ethApp.addresses(networkId) - second value of tuple is asset id
- 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
Substrate extrinsics
Ethereum contract functions
Contracts ABI
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
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
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