Given one of the core USPs of Polkadot is its modularity and interoperability, it should be relatively easy to allow assets/tokens to be transferred between chains via XCM

My question is about what is the "best practice". Is there one defined?

I think we ideally need to make it simple and straightforward to import an asset from one chain to another and while the UI work needs to be done, we need a consistent way of allowing new chains to add another's chains tokens into their runtime

As far as I can tell there are 2 ways to do this

  1. Assets Pallet
  2. ORML-Tokens

While I understand the need to not have substrate be opinionated and allow chains the freedom to implement a registry as they see fit, I think defining a guide/tutorial or a best practice will go a long way.

Very similar to how the substrate-node-template onboarded so many engineers and teams

There is already an issue raised on here. Please feel free to comment/help if you are interested

  • I think people are having a hard time answering this question because best practices are probably yet to emerge; cross-chain transfers are relatively new in Polkadot and Kusama and strong development patterns will only occur after a learning period.
    – rob
    Apr 7, 2022 at 17:49

2 Answers 2


This is a slightly more complex subject than it sounds. The reason is that while Polkadot guarantees the correct execution of each parachain's logic, it does not guarantee that the logic does something sensible or expected by some particular set of onlookers.

An obvious example would be teleports. The act of teleporting is basically the act of burning a token on one sending chain and at some point in the near future creating a token representing that destroyed asset on a receiving chain. One instance of this would be sending DOT from the Polkadot Relay-chain to the Statemint parachain: The DOT is destroyed on the Relay-chain and created on Statemint. It can be teleported back which involves it being destroyed on Statemint and minted again on the Relay-chain.

It is fairly easy to construct an XCM message to do this, and the XCM pallet in Cumulus includes such a facility to do just this (search for fn teleport_assets). However, there is nothing embedded in the Polkadot protocol which stops the sending chain from sending a message to tell the "recipient" chain to mint a particular asset without actually destroying the corresponding asset. The reason we do teleporting between the Relay-chain and Statemint is because the Relay-chain is in complete control of Statemint's logic via governance, and thus it can trust Statemint to behave as expected.

The same cannot be said of arbitrary teams' parachains. Without even getting into malicious intent, an innocent bug could cause a parachain to inadvertently send unfaithful teleport counterparts, instructing the minting of tokens on receiving chains which never existed on the sending chain.

To manage this there are two solutions:

  • SPREE (Secure Parachain Runtime Execution Enclaves), which allows for non-negotiable, individually addressable identical instances of logic modules (basically, pallets) to exist on parachains, thereby alleviating the need for one parachain to trust another's logic. This is not yet implemented but is at the design stage.
  • Reserve Assets, the current solution, which is essentially to name a particular chain as the universally trusted home for an asset. When this asset "exists" on any chain which is not the home-chain, it in fact is just an IOU (or fully-backed derivative) which can be traded in for an instance of the real asset which exists on the home-chain.

When SPREE is delivered then the answer to this question will basically just be "have your parachain opt-in to the assets SPREE module". Until then, it's a little harder. Teleporting can work if both your parachain and the parachain from which you wish to receive the given asset trust each other's logic (to the point of bankrupting eachother if there is a bug in one). This level of trust between parachains isn't usually the case, but might work if a single parachain team end up deploying to multiple parachains. Otherwise we're basically stuck with reserve asset transfers. Right now for these to work, each asset must be configured individually with the fungible implementation in the runtime together with the home-chain on which the actual asset sits.

This is only a temporary solution. Changes which are part of the XCMv3 upgrade will bring along the possibility of automating the ability to receive, host and send foreign assets without requiring those assets to be explicitly configured in the runtime. There is already an example of this in the XCM v3 branch using the Uniques pallet CreateOrigin and MultiLocations as a means of identifying a foreign NFT by its relative location.

  • Thank you so much Gav! Very clear and I understand why all chains are using reserve assets
    – Sam Elamin
    May 5, 2022 at 9:10

Assets pallet and ORML tokens are not related to the cross-chain transfer of assets, instead they are just slightly different ways to store balances in chains supporting more than one kind of fungible token, both implement the frame_support::traits::fungibles.

For the cross chain transfer you would build an XCM with the right set of instructions(i.e. something including InitiateTeleport, TransferReserveAsset and the likes). But crafting an XCM is not always straightforward so to answer your question, I'd say orml-xtokens is a good "standard way" to do cross chain transfer of assets, you can integrate it with either orml-tokens or pallet-assets and it will handle the annoying parts of constructing the right XCM to do a reserve asset transfer.
I asset registry from the linked issue doesn't solves the issue of importing the tokens to your chain but It might help deciding what to do with some tokens that just arrived to your chain(e.g. via xtokens), I imagine in the case of orml-tokens you could use the registry to decide what AssetId to use based on a MultiLocation, with pallet-assets you could also use the metadata of your registry to create a new asset class. You should also have an AssetId that is flexible enough to represent different kinds of assets coming from diffrent chains, e.g. a bit number like u64, or a more descriptive type like

enum Asset {

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.