Using AssetHub
The relay chain does not natively support assets beyond its native token. This functionality exists in parachains. On both Polkadot and Kusama, this parachain is called Asset Hub.
The Asset Hub provides a first-class interface for creating, managing, and using fungible and non-fungible assets. The fungible interface is similar to Ethereum's ERC-20 standard. However, the data structures and stateful operations are encoded directly into the chain's runtime, making operations fast and fee-efficient.
Beyond merely supporting assets, integrating an Asset Hub into your systems has several benefits for infrastructure providers and users:
- Support for on-chain assets.
- Significantly lower transaction fees (about 1/10) than the relay chain.
- Significantly lower deposits (1/100) than the relay chain. This includes the existential deposit and deposits for proxy/multisig operations.
- Ability to pay transaction fees in certain assets. As in, accounts would not need DOT to exist on-chain or pay fees.
The Asset Hub will use DOT as its native currency. Users can transfer DOT from the relay chain into the Asset Hub and use it natively. The relay chain will also accept DOT transfers from the Asset Hub back to the relay chain for staking, governance, or any other activity.
Using the Asset Hub for DOT/KSM balance transfers will be much more efficient than the relay chain and is highly recommended. Until domain-specific parachains are built, the relay chain will still need to be used for staking and governance.
Assets Basicsβ
See the Assets pallet for the most up-to-date info and reference documentation.
Assets are stored as a map from an ID to information about the asset, including a management team, total supply, total number of accounts, its sufficiency for account existence, and more. Additionally, the asset owner can register metadata like the name, symbol, and number of decimals for representation.
Some assets, as determined by on-chain governance, are regarded as βsufficientβ. Sufficiency means that the asset balance is enough to create the account on-chain, with no need for the DOT/KSM existential deposit. Likewise, you cannot send a non-sufficient asset to an account that does not exist. Sufficient assets can be used to pay transaction fees (i.e. there is no need to hold DOT/KSM on the account).
Assets do have a minimum balance (set by the creator), and if an account drops below that balance, the dust is lost.
Asset Operationsβ
The Assets pallet has its interface for dealing with assets. See the Integration section below for how to fetch information and construct transactions.
The main functions you will probably interact with are transfer
and transfer_keep_alive
. These
functions transfer some amount
(balance) of an AssetId
(a u32
, not a contract address) to
another account.
The Assets pallet also provides an approve_transfer
, cancel_approval
, and transfer_approved
interface for non-custodial operations.
Asset transfers will result in an assets.transferred
event. The same instructions for
monitoring events and not transactions applies to asset
transfers.
Note that you can use the same addresses (except pure proxies!) on the Asset Hub that you use on the relay chain. The SS58 encodings are the same; only the chain information (genesis hash, etc.) will change on transaction construction.
Paying Transaction Fees in Another Assetβ
Users in the Asset Hub can pay the fees of their transactions with assets other than DOT. The only requirement is that a liquidity pool of the relevant asset against DOT should already exist as a storage entry of the Asset Conversion pallet.
Technically speaking, this is enabled by
the ChargeAssetTxPayment
signed-extension
implemented in the Asset Hub runtime. This signed-extension extends transactions to include an
optional AssetId
that specifies the asset to be used for payment of both the execution fees and
the optional tip. It defaults to the native token when it is set to None
. In case it is given,
this AssetId
has to be an
XCM Multilocation
. Once the transaction
is executed in the block, it will emit an AssetTxFeePaid
event, informing of the account paying
the fees, the amount in the asset paid as fee, the tip (if any), and the asset ID of the asset
paying the fees.
Handling Pools with Low Liquidity
Wallets and UIs enabling this functionality should ensure that the user is prompted with the necessary warnings, such that they do not accidentally spend all of their funds to perform a swap on a pool with no or low liquidity.
How to Build Transactions Paying Fees with Other Assetsβ
- This repository contains the complete workflow on how to create a liquidity pool for a given asset, add liquidity to it and then build a transaction to pays fees with this asset (including fees estimation). It is done with several libraries: Polkadot-JS API and Subxt.
- Example using Asset Transfer API to do a cross-chain transfer in Polkadot Asset Hub paying fees with GLMR.
- A simple script using Polkadot-JS API to do a local transfer of bridged KSM in Polkadot Asset Hub paying fees with USDT.
Foreign Assetsβ
Foreign assets are those assets in Asset Hub whose native blockchain is not Asset Hub. These are mainly native tokens from other parachains or bridged tokens from other consensus systems (such as Ethereum). Once a foreign asset has been registered in Asset Hub (by its root origin), users are enabled to send this token from its native blockchain to Asset Hub and operate with it as if it were any other asset.
Practically speaking, foreign assets are handled by the foreign-assets
pallet in Asset Hub, which
is an instance of the Assets pallet. Hence, this pallet exposes the same interface to users and
other pallets as the Assets pallet.
The main difference to take into account for foreign assets is their identifier. Instead of using
integers as identifiers like in the Assets pallet, assets stored in the foreign-assets
pallet are
identified by
their XCM multilocation.
Integrationβ
The Asset Hub will come with the same tooling suite that Parity Technologies provides for the Relay Chain, namely API Sidecar and TxWrapper Polkadot, as well as the Asset Transfer API. If you have a technical question or issue about how to use one of the integration tools, please file a GitHub issue so a developer can help.
Parachain Nodeβ
Using the Asset Hub will require running a parachain node to sync the chain. This is very similar to running a relay chain node, with the addition of some extra flags. You can follow these guidelines to set up an Asset Hub node.
Asset Transfer APIβ
Asset-transfer-api is a library focused on simplifying the construction of asset transfers for Substrate-based chains that involve system parachains like Asset Hub (Polkadot and Kusama). It exposes a reduced set of methods that facilitate users to send transfers to other (para) chains or locally. You can refer to this table for the current cross-chain support and here for the complete documentation, including installation guide and usage examples.
Sidecarβ
API Sidecar is a REST service for relay chain and parachain nodes. It comes with endpoints to query information about assets and asset balances on the Asset Hub.
- Asset lookups always use the
AssetId
to refer to an asset class. On-chain metadata is subject to change and thus unsuitable as a canonical index. - Please refer to docs for full usage information. Details on options like how to make a historical query are not included here.
Here are the available public instances:
The purpose of these instances is to allow anyone to check and get a quick overview of the info that the asset-related endpoints provide.
These instances should only be used for ad-hoc checks or tests and not for production, heavy testing or any other critical purpose.
Tx Wrapper Polkadotβ
TxWrapper Polkadot is a library designed to facilitate transaction construction and signing in
offline environments. It comes with asset-specific functions to use on the Asset Hub. When
constructing parachain transactions, you can use txwrapper-polkadot
exactly as on the relay chain,
but construct transactions with the appropriate parachain metadata like genesis hash, spec version,
and type registry.
XCM Transfer Monitoringβ
Monitoring of XCM depositsβ
Thanks to XCM and a growing number of parachains, the relay chain native token can exist across
several blockchains, which means the providers need to monitor cross-chain transfers on top of local
transfers and corresponding balances.transfer
events.
Currently, DOT can be sent and received in the relay chain and in the Asset Hub either with a
Teleport from
system parachains or with a
Reserve Backed Transfer
from any other parachain. In both cases, the event emitted when processing the transfer is the
balances.minted
event. Hence, providers should listen to these events, pointing to an address in
their system. For this, the service provider must query every new block created, loop through the
events array, filter for any balances.minted
event, and apply the appropriate business logic.
Tracking back XCM informationβ
What has been mentioned earlier should be sufficient to confirm that DOT has arrived in a given
account via XCM. However, in some cases, it may be interesting to identify the cross-chain message
that emitted the relevant balances.minted
event. This can be done as follows:
- Query the relevant chain
at
the block thebalances.minted
event was emitted. - Filter for
messageQueue(Processed)
events. These can be emitted during any phase of the block, not just initialization. This event has a parameterId
. The value ofId
identifies the cross-chain message received in the relay chain or in the Asset Hub. It can be used to track back the message in the origin parachain if needed. Note that a block may contain severalmessageQueue(Processed)
events corresponding to several cross-chain messages processed for this block.
Additional Examples of Monitoring XCM Transfersβ
The two previous sections outline the process of monitoring XCM deposits to specific account(s) and then tracing back the origin of these deposits. However, the process of tracking an XCM transfer (hence the events to look for) may vary based on the direction of the XCM message. Here are some examples to showcase the slight differences:
-
For an XCM transfer from a Parachain to a relay chain (example):
- The event to look for in the
Parachain side is called
parachainsystem (UpwardMessageSent)
, and the parametermessage_hash
in this event identifies the XCM transfer. - The event to track in
the relay chain side is called
messagequeue (Processed)
, and the parameterid
of the event should be the same as themessage_hash
found in the Parachain event.
- The event to look for in the
Parachain side is called
-
For an XCM transfer from a relay chain to a parachain (example):
- The event to look for in
the relay chain side is called
xcmPallet (sent)
, and the parametermessage_id
in this event identifies the XCM transfer. - The event to look for in the
Parachain side is called
dmpqueue (ExecutedDownward)
, and the parameter that identifies the XCM message is either calledmessage_hash
ormessage_id
.
- The event to look for in
the relay chain side is called
-
For an XCM transfer from a System Parachain to a Parachain (example):
- The event to look
for in the System Parachain side is called
xcmpqueue (XcmpMessageSent)
, and again themessage_hash
is one of the parameters of the event. - The corresponding event in
the Parachain side is the
xcmpqueue (Success)
and themessage_hash
found in that event should have the same value as the one in the System parachain.
- The event to look
for in the System Parachain side is called
Monitoring of Failed XCM Transfersβ
In case that an XCM transfer fails to complete successfully, then we will notice some different parameters in the events emitted or different events. Below are some examples:
-
From a relay chain to a System Parachain (example):
- We will see the
event
dmpqueue (ExecutedDownward)
in the System Parachain side with the following parameters:outcome
with valueIncomplete
and with the type of error which in this example is UntrustedReserveLocation.message_id
which shows the hash of the XCM Transfer.
- We will see the
event
-
From a Parachain to another Parachain (example):
- We will see the event
xcmpqueue (Fail)
in the destination Parachain with the following parameters:error
which in this example is TooExpensive.message_hash
which identifies the XCM Transfer.
- Note: there might be another
event called
polkadotxcm (AssetsTrapped)
which indicates that some assets have been trapped (and hence can be claimed).
- We will see the event
A great resource to learn more about Error Management in XCM is the Polkadot blog post from Gavin Wood, XCM Part III: Execution and Error Management.