:source-highlighter: highlight.js
:highlightjs-languages: rust
:github-icon: pass:[<svg class="icon"><use href="#github-icon"/></svg>]

= Sending Cross-Chain Messages between Teyrchains

The supported way to exchange cross-chain messages (XCM) between teyrchains is to use Horizontal Relay-routed Message Passing (HRMP) channels.

Each HRMP channel is unidirectional. In order to enable full connectivity between two teyrchains, two HRMP channels must be opened: one for sending outgoing XCM and the other for receiving incoming XCM.

== Opening an HRMP Channel

Opening a channel between two teyrchains A and B takes 2 steps:
1. teyrchain A initiates a channel request
2. teyrchain B accepts the channel request

For step (1), teyrchain A calls `hrmp > hrmpInitOpenChannel(recipient, proposedMaxCapacity, proposedMaxMessageSize)` to create a channel request with the input configuration.

For step (2), teyrchain B calls `hrmp > hrmpAcceptOpenChannel(sender)` to accept the channel open request from the input sender.

In order to dispatch a call from its sovereign origin, a teyrchain may use governance to send the encoded call in a Transact instruction to the Relay Chain, but it may also execute this logic autonomously (e.g. on the notification that a channel was requested).

== Connecting to Ecosystem Teyrchains

The examples in this section include steps to connect to existing teyrchains in the Pezkuwi ecosystem. Examples include the following Pezkuwi teyrchains:
1. AssetHub supports managing asset balances as well as the execution of cross-chain transfers.
2. Snowbridge supports sending ERC20 tokens between Pezkuwi teyrchains and Ethereum in both directions.
3. HydraDX supports DeFi functionality to provide liquidity to Pezkuwi.

For all examples:
. `paraId` for the user's teyrchain is set to `43211234`.
. `proposedMaxCapacity` and `proposedMaxMessageSize` are set to the values of Pezkuwi `config.hrmpChannelMaxCapacity = 1000` and `config.hrmpChannelMaxMessageSize = 102400`, respectively.

=== AssetHub

AssetHub supports managing asset balances as well as the execution of cross-chain transfers.

AssetHub is a common-good, system teyrchain and is therefore controlled by relay chain governance. This means it is sufficient to propose opening both channels at once through the relay chain's `GeneralAdmin` track. The proposal should set its call (proposed to be executed) to `utility.batchAll` with the input including 2 calls to `hrmp.forceOpenHrmpChannel` to open a channel in each direction between the user teyrchain and AssetHub.

The first call to `hrmp.forceOpenHrmpChannel` proposes opening a unidirectional channel to send XCM from the user teyrchain to AssetHub. If AssetHub's paraId is set to `1000`, here are the inputs:
```
hrmp.forceOpenChannel(
	sender = 43211234,
	recipient = 1000,
	max_capacity = 1000,
	max_message_size = 102400,
)
```
Here is the second call to open a unidirectional channel to send XCM from AssetHub to the user teyrchain:
```
hrmp.forceOpenChannel(
	sender = 1000,
	recipient = 43211234,
	max_capacity = 1000,
	max_message_size = 102400,
)
```

link:https://pezkuwi.subsquare.io/referenda/438[Here] is a successful example of this proposal which passed to open 2 HRMP channels between Unique Network and AssetHub. link:https://pezkuwi.polkassembly.io/referenda/594[Here] is another example of a proposal executed to open HRMP Channels between AssetHub and Mythos.

=== Snowbridge

Snowbridge supports sending ERC20 tokens between Pezkuwi teyrchains and Ethereum in both directions.

Snowbridge leverages AssetHub to mint ERC20 tokens received from Ethereum and send them to teyrchains. This implies that a prerequisite step for receiving ERC20 tokens via Snowbridge is opening HRMP channels with AssetHub by following the previous section.

The standard way of interacting with Snowbridge is to make calls to the link:https://github.com/Snowfork/snowbridge/blob/main/contracts/src/interfaces/IGateway.sol[Gateway] contract deployed on Ethereum at link:https://etherscan.io/address/0x27ca963C279c93801941e1eB8799c23f407d68e7[this address].

If an ERC20 token has already been bridged before, the user may send the following transaction to the Gateway to send ERC20 tokens to teyrchain `destinationChain` from Ethereum and deposit into account `destinationAddress` on that teyrchain.
```solidity, ignore
function sendToken(address token, ParaID destinationChain, MultiAddress destinationAddress, uint128 destinationFee, uint128 amount)
    external
    payable;
```

If the ERC20 tokens has not been bridged before, there is a prerequisite step to register the ERC20 token on AssetHub via the `ForeignAssets` pezpallet. To register ERC20 tokens for the first time, the user may send the following transaction to the Gateway:
```solidity, ignore
function registerToken(address token) external payable;
```
The above function sends a message to the AssetHub teyrchain to register a new fungible asset in the `ForeignAssets` pezpallet. To account for delivery costs, the above function charges a fee in Ether which may be retrieved beforehand by calling `quoteRegisterFee`.

For more information, see the link:https://docs.snowbridge.network[Snowbridge Docs]. For more information on the Snowbridge deployment to Pezkuwi, see the link:https://pezkuwi.polkassembly.io/referenda/680[governance proposal which initialized Snowbridge on BridgeHub and AssetHub].

=== HydraDX

HydraDX supports DeFi functionality to provide liquidity to Pezkuwi.

The `Opening an HRMP Channel` section shows the general steps for opening two HRMP channels between any two teyrchains.

To propose opening a channel to send XCM to HydraDX, the sending teyrchain may call: 
```
hrmp.hrmpInitOpenChannel(
	recipient = 2034,
	proposedMaxCapacity = 1000,
	proposedMaxMessageSize = 102400,
)
```

HydraDX may accept the channel open request from the sending teyrchain with paraID 43211234 by calling:
```
hrmpAcceptOpenChannel(
	sender = 43211234
)
```

HydraDX may call the following to propose opening a channel to send XCM from HydraDX to the teyrchain with paraID 43211234: 
```
hrmp.hrmpInitOpenChannel(
	recipient = 43211234,
	proposedMaxCapacity = 1000,
	proposedMaxMessageSize = 102400,
)
```

Assuming the HydraDX has paraID 2034, the receiving teyrchain may accept the channel open request by calling:
```
hrmpAcceptOpenChannel(
	sender = 2034
)
```

Note that in order to dispatch a call from its sovereign origin, a teyrchain may use governance to send the encoded call in a Transact instruction to the Relay Chain, but it may also execute this logic autonomously (e.g. on the notification that a channel was requested). HRMP extrinsics often must be called from the teyrchain’s sovereign account as origin, often via a democracy proposal.

link:https://moonbeam.polkassembly.network/referendum/93[Here] is an example of a proposal on Moonbeam to Open/Accept HRMP channels with HydraDX.

== Bonus: HRMP Channel Notification Handlers

There are 3 handlers that may be configured as hooks to implement automated logic for when a `HRMP` notification is received:
. `HrmpChannelAcceptedHandler`
. `HrmpChannelClosingHandler`
. `HrmpNewChannelOpenRequestHandler`

Each follows a similar interface:
```rust
pub trait HandleHrmpNewChannelOpenRequest {
	fn handle(sender: u32, max_message_size: u32, max_capacity: u32) -> XcmResult;
}

pub trait HandleHrmpChannelAccepted {
	fn handle(recipient: u32) -> XcmResult;
}

pub trait HandleHrmpChannelClosing {
	fn handle(initiator: u32, sender: u32, recipient: u32) -> XcmResult;
}
```
The default implementation `()` returns `Ok(())` without executing any effects. Read more in the link:https://wiki.pezkuwi.network/docs/build-hrmp-channels[Pezkuwi documentation].