The goal of this repository is to describe and provide samples of all possible XCM interactions between Parachains, Relay Chains, and also an optional Bridged counterpart context. The samples are written in TypeScript and connect to a locally deployed infra thanks to Polkadot JS API.
The necessary infra to run and test the samples can be easily deployed with a single command. This repository depends on:
- Polakadot - Relay Chain
- Cumulus - Parachain
- Bridges Common - Bridge Relayers (optional)
Note that the three projects are in continous development. For that reason, it is very important to pay attention on using compatible versions between them. In addition, since XCM versioning and configuration differs for each runtime, it becomes an extra factor to take into account when running or building new samples.
To make sure you are able to successfully run the samples locally, checkout to one of the available releases in this repository. The release name format defines what are the compatible versions you should checkout for the rest of respositories and what runtimes were used.
Release format:
release-<polkadot/cumulus_version>-<source_para_runtime>_<source_relay_runtime>-<target_relay_runtime>_<target_para_runtime>-<bridges_common_version>
For instance, release-0.9.10-rococo_rococo-wococo_rococo-0.9
is telling us that the release was tested against the following versions
- Polkadot:
release-v0.9.10
- Cumulus:
polkadot-v0.9.10
- Relay Chain Runtimes:
rococo-local
andwococo-local
- Parachains Runtimes:
rococo-local
andrococo-local
- Bridges Common:
v0.9
There might be cases where a certain runtime is not yet supported by Bridges Common, or we just do not want to implement it. Therefore, Bridges Common and a target runtimes are not necessary. For those cases, release-0.9.10-rococo_rococo
woulde be telling us that the release was tested against the following versions
- Polkadot:
release-v0.9.10
- Cumulus:
polkadot-v0.9.10
- Relay Chain Runtime:
rococo-local
- Parachains Runtime:
rococo-local
Unless you want to run the samples against unimplemented runtimes, the default values should be valid and the only variables you should update in ./config.sh
are:
POLKADOT_REPO_PATH
,PARACHAIN_REPO_PATH
andBRIDGES_REPO_PATH
point to the directories where the three previously mentioned repositories were cloned. Remember also to checkout the corresponding versions.
To change the Relay Chain runtimes:
RUNTIME_RELAY_SOURCE=<source_relay_runtime>
RUNTIME_RELAY_TARGET=<target_relay_runtime>
To change the Parachains runtimes:
RUNTIME_PARA_SOURCE=<source_para_runtime>
RUNTIME_PARA_TARGET=<target_para_runtime>
$ ./start.sh
$ ./stop.sh
Relay Chains have a few different mechanisms that are responsible for message passing. They can be generally divided on two categories: Horizontal and Vertical. Horizontal Message Passing (HMP) refers to mechanisms that are responsible for exchanging messages between parachains. Vertical Message Passing (VMP) is used for communication between the relay chain and parachains.
All previous mechanisms can also be encapsuladed in a bridge message and executed "remotely" in a target context.
- A bridge message payload is formed by:
const payload = { call origin spec_version weight }
call
: The encoded call data of the XCM to be executed in the Target Relay Chainorigin
: Defines the Call origin to be used during the dispatch in the Target Relay Chain. There are three types:SourceAccount
: represents an account without a private key on the target-chain. This account (Companion Account) will be generated/derived using the account ID of the sender on the source-chain.TargetAccount
: represents an account with a private key on the target-chain. The sender on the source-chain needs to prove ownership of this account by using their target-chain private key to sign a proof.SourceRoot
: represents the source-chain's Root account on the target-chain. This origin can only be dispatched on the target chain if the "send message" request was made by the Root origin of the source chain - otherwise the message will fail to be dispatched
spec_version
: The expected Target Relay Chain runtime version. Message will not be dipatched if it does not match.weight
: Weight of the call, declared by the message sender. If it is less than actual static weight, the call is not dispatched.
- A
bridgeMessages.sendMessage(laneId, payload, deliveryAndDispatchFee)
extrinsic is signed and sent by an origin in the source context. The bridge message pallet name varies based on the runtime implementation and the name of the Target Relay Chain it is aiming to send the message. For example, for Rococo runtime the pallet name to bridge to Wococo isbridgeWococoMessages
. Althought the bridge pallets might have different naming, all of them are instances ofpallet_bridge_messages
. - If the Message is accepted, it is stored on-chain in the
OutboundMessages
storage. - The Bridge Message Relayer queries the Messages Outbound Lane from the Source Relay Chain and pass the message over to the Messages Inbound Lane of the Target Relay Chain
- Finally, the XCM message is picked up from the Inbound Lane and dispatched by the corresponding
pallet_bridge_dispatch
in the Target context.
Downward Message Passing (DMP) is a mechanism for delivering messages to parachains from the relay chain.
- XCM encoded call and messages payload are generated
- Bridge Message is signed and sent with the XCM encoded call as part of its payload
- Message is accepted and stored in
OtboundMessages
- The Bridge Message Relayer query the message from the Source Relay Chain Outbound Lane and pass it over the Target Relay Chain
- The XCM enconded call is dispatched in the Target Relay Chain
Upward Message Passing (UMP) is a mechanism responsible for delivering messages in the opposite direction: from a parachain up to the relay chain.
A Comand Line Interface is available to run the samples. The command has the following format:
yarn dev <MESSAGING> <TARGET> [OPTIONS] <XCM> [OPTIONS]
-
MESSAGING
: mechanism for message passingdmp
: Downward Message Passingump
: Upward Message Passinghmp
: Horizontal Message Passing
-
TARGET
: context the message is going to be executedlocal
: the message is executed in the Source Chainremote
: the message is passed through the bridge to the Target Chain and executed there.-l
: bridge message lane |0x00000000
(Default)-f
: fee |10000000000000
(Default)-o
: origin |SourceAccount
(Default)
-
XCM
: XCM instruction type. All instructions butteleport-asset
will fallback to thesend()
dispatchable from thexcmPallet
teleport-asset
: call to theteleportAsset()
dispatachable call from thexcmPallet
-p
: parachain ID destiantion |2000
(Default)-s
: extrinsic signer account (uri or private key) |//Alice
(Default)-b
: beneficiary account-a
: amount to teleport-w
: destination weight
transact
:Transact
-p
: parachain ID destiantion |2000
(Default)-s
: extrinsic signer account (uri or private key) |//Alice
(Default)-t
: origin typeSovereignAccount
Native
Superuser
Xcm
-c
: encoded call to be executed in the parachain target-w
: required weight at most
yarn dev dmp local teleport-asset -s //Alice -p 2000 -b //Bob -a 1000000000000000 -w 100000000000
- Alice signs and sends a
xcmPallet.teleportAssets(destination, beneficiary, assets, destWeight)
extrinsic - A
WithdrawAsset
XCM is executedAsset
amount is withdrawn from Alice and deposited in the Check Account - A
InitiateTeleport
XCM with two effects (BuyExecution
andDepositAsset
) is stored in the Relay Chain storage - The XCM is read from the Relay Chain storage by the Parachain Full Node
InitiateTeleport
is executed,Asset
amount is minted and deposited in Bob's account.
-
SourceAccount
: The Xcm is executed by the Companion Account in the target Relay Chain. Therefore, the Companion Account should have some balance (1K at least for the following sample).//Alice
Companion Account in Wococo is:5GfixJndjo7RuMeaVGJFXiDBQogCHyhxKgGaBkjs6hj15smD
yarn dev dmp remote -f 10000000000000 -l 0x00000000 teleport-asset -s //Alice -p 2000 -b //Bob -a 1000000000000000 -w 100000000000
-
TargetAccount
: The Xcm is executed by an owned account in the target Relay Chainyarn dev dmp remote -o TargetAccount -t //Alice -f 10000000000000 -l 0x00000000 teleport-asset -s //Alice -p 2000 -b //Bob -a 1000000000000000 -w 100000000000
Only Root Account (sudo) is able to send a Transact
XCM to a Parachain. The Call will be dispatched by the Sovereign Account in the Parachain
Thus, the source Sovereign Account, 5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM
should have some balance (1K at least for the following sample)
The encoded Call
that Transact
instruction will dispatch is 0x1e00008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480f0080c6a47e8d03
and corresponds to balance.transfer()
of 1k to //Bob
yarn dev dmp local transact -s //Alice -p 2000 -t SovereignAccount -w 1000000000 -c 0x1e00008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480f0080c6a47e8d03
- The encoded call
balance.transfer(dest, value)
to be executed by theTransact
XCM is generated. - The
Transact
XCM is formed withoriginType = SovereignAccount
const xcm = { Transact: { originType, requireWeightAtMost, encodedCall } }
- Alice signs and send the extrinsic
sudo.sudo(api.tx.xcmPallet.send(destination, xcm))
- The
Transact
XCM is stored in the Relay Chain - The XCM is read from the Relay Chain storage by the Parachain Full Node
- The encoded call in the
Transact
XCM is executed in the Parachain by its Sovereign Account, transfering the balance value to Bob
NOTE: Sending a Transact
with a encoded bridgeWococoMessages.sendMessage()
dispatch is not possible as the bridge pallet is only implemented in the Parachain. Therefore, DMP messages are not possible. Only a UMP or HMP would work. The alternative would be to try to send a Transact
with destination Here
instead of the Parachain.
-
SourceAccount
: This case is not possible because aTransact
XCM can only be executed by Root. -
TargetAccount
: The Root Account private key of the target key should be know to be able to use this option. The Sovereign Account5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM
of the target Parachain should have some balance.yarn dev dmp remote -o TargetAccount -t //Alice -f 10000000000000 -l 0x00000000 transact -s //Alice -p 2000 -t SovereignAccount -w 1000000000 -c 0x1e00008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480f0080c6a47e8d03