Skip to content

Pallet Token Gateway

This is an ISMP module that allows standalone chains or parachains make and receive cross chain asset transfers.

Config

Let's look at the pallet specific components of the configuration trait:

  • Dispatcher: The should be an implementation of the IsmpDispatcher, it will be used by this pallet dispatch cross-chain requests.

  • Assets: This type should be configured with a component that implements the following interfaces, typically this will be pallet-assets
  • Currency: This type should be configured with a component that implements Currency interface, typically pallet-balances.

  • AssetAdmin: This pallet has some functionality for creating new assets. The account configured for this type would be the asset admin and also be responsible for paying the asset registration fees, therefore it should be funded before attempting to create any assets.

  • AssetIdFactory: This type should be configured with a component that implements pallet_token_gateway::types::CreateAssetId. It should return a unique asset id each time the AssetIdFactory::create_asset_id is called.

  • NativeAssetId: A constant value that represents the identifier of the native asset.

  • Decimals: A constant that represents the precision of the native currency.

Calls

  • teleport: This call is used to initialize a cross-chain asset transfer. Any provided assets are custodied by the pallet and a cross-chain request is dispatched to the destination chain.
  • set_token_gateway_addresses: This priviledged call is used to set the token gateway address for EVM chains.
  • create_erc6160_asset: This call dispatches a request to Hyperbridge to create multi chain native assets on token gateway deployments
  • update_erc6160_asset: This call dispatches a request to Hyperbridge to update multi chain native assets on token gateway deployments

Priviledged calls must be dispatched by AdminOrigin configured in pallet-ismp.

Integrating the pallet into the Runtime

The first step is to implement the pallet config for the runtime.

use frame_support::parameter_types;
use ismp::module::IsmpModule;
use ismp::router::IsmpRouter;
 
parameter_types! {
    // A constant that should represent the native asset id, this id must be unique to the native currency
    pub const NativeAssetId: u32 = 0; 
    // Set the correct decimals for the native currency
    pub const Decimals: u8 = 12;
}
 
/// Should provide an account that is funded and can be used to pay for asset creation
pub struct AssetAdmin;
 
impl Get<AccountId> for AssetAdmin {
	fn get() -> AccountId {
		Treasury::account_id()
	}
}
 
impl pallet_token_gateway::Config for Runtime {
    // configure the runtime event
    type RuntimeEvent = RuntimeEvent;
    // Configured as Pallet Ismp 
    type Dispatcher = Ismp;
    // Configured as Pallet Assets
	type Assets = Assets;
    // Configured as Pallet balances
	type Currency = Balances;
    // AssetAdmin account
    type AssetAdmin = AssetAdmin;
    // The Native asset Id
	type NativeAssetId = NativeAssetId;
    // A type that provides a function for creating unique asset ids
    // A concrete implementation for your specific runtime is required
    type AssetIdFactory = ();
    // The precision of the native asset
    type Decimals = Decimals;
}
 
// Add the token gateway pallet to your ISMP router
#[derive(Default)]
struct Router;
impl IsmpRouter for Router {
    fn module_for_id(&self, id: Vec<u8>) -> Result<Box<dyn IsmpModule>, anyhow::Error> {
        let module = match id.as_slice() {
            id if TokenGateway::is_token_gateway(&id) => Box::new(TokenGateway::default()),
            _ => Err(Error::ModuleNotFound(id))?
        };
        Ok(module)
    }
}

Setting up Token Gateway

Setting up token gateway for use involves a few simple steps.

  1. Registering token gateway addresses on EVM chains
    The pallet needs to know the addresses of the token gateway contracts on EVM chains, so it can validate the source of incoming messages.

    This requires dispatching the set_token_gateway_addresses extrinsic from AdminOrigin configured in pallet-ismp.
    This call accepts a map of StateMachine to Vec<u8>, this is only neccessary for validating messages coming from EVM chains, all substrate chains use a static token gateway address. Find the required addresses here

  2. Registering assets on token gateway deployments
    For transfer of the native currency and other assets issued on your chain through token gateway, those assets need to be registered on the token gateway asset registry on hyperbridge The process of registering assets involves dispatching a request to create the asset on hyperbridge after which hyperbridge dispatches requests to deploy the asset on all chains specified in the initial request.

    The types involved in asset creation are described below:

pub struct GatewayAssetRegistration {
	/// The asset name
	pub name: BoundedVec<u8, ConstU32<20>>,
	/// The asset symbol
	pub symbol: BoundedVec<u8, ConstU32<20>>,
	/// The list of chains to create the asset on
	pub chains: Vec<StateMachine>,
	/// Minimum balance for the asset, for substrate chains,
	pub minimum_balance: Option<u128>,
}
 
pub struct AssetRegistration<AssetId> {
	/// The asset must exist locally
	pub local_id: AssetId,
	/// Asset metadata
	pub reg: GatewayAssetRegistration,
}

To register assets on token gateway you need to dispatch the create_erc6160_asset extrinsic with an AssetRegistration<AssetId> object.
The former contains the local asset id and the asset metadata.

GatewayAssetRegistration

This is the core struct that holds the metadata of the asset you need to register.

name: This should be the full name of the asset, it's limited to 20 characters.

symbol: This is the ticker for the asset, also limited to 20 characters. The asset Id will be derived from the keccak256 hash of this value.

chains: This is a vector of the chains you want this asset deployed. It should be only chains supported by hyperbridge network.

minimum_balance: This value is only necessary when you intend to deploy this asset on a substrate chain. It represents the minimum amount of the asset that an account can hold on susbtrate based chains.

A local asset id must be provided for the asset so it ca be mapped to the token gateway asset id.

To register the native currency(pallet-balances) on token gateway you need to set the local_id field in the AssetRegistration<AssetId> to the same constant that was specified as the NativeAssetId in the pallet config along with the required metadata.
Assets can also be updated in the same way by dispatching update_erc6160_asset.

Asset Ids

Token gateway protocol represents assets ids with a 32 byte hash which is derived from the keccak256 hash of the asset's symbol.

Teleporting assets

To make a crosschain transfer the teleport extrinsic should must be dispatched with the correct parameters.

pub struct TeleportParams<AssetId, Balance> {
	/// Asset Id registered on Hyperbridge
	pub asset_id: AssetId,
	/// Destination state machine
	pub destination: StateMachine,
	/// Receiving account on destination
	pub recepient: H256,
	/// Amount to be sent
	pub amount: Balance,
	/// Request timeout
	pub timeout: u64,
	/// Token gateway address
	pub token_gateway: Vec<u8>,
	/// Relayer fee
	pub relayer_fee: Balance,
}

Let's explore what each parameter holds:

  • asset_id: The local asset id for the asset that should be transferred
  • destination: The destination chain that should receive the funds
  • recepient: The beneficiary account for the funds on the destination. (For EVM chains, the address should be left padded with zeros to fit into the required 32 bytes.)
  • amount: The amount that should be transferred.
  • timeout: The request timeout, this is the time after which the request cannot be delivered to the destination. It should represent the cumulative time for finalization on the source chain and hyperbridge with some additional buffer.
  • token_gateway: The address of the token gateway module on the destination chain.
  • relayer_fee: The amount to be paid to relayers for delivering the request, a value of zero means the dispatcher is responsible for relaying the request.

Funds from undelivered requests can be recovered by submitting a timeout message for the request through pallet-ismp.