Messaging
Send your first interchain message in under 5 minutes
This tutorial demonstrates how to:
$RECIPIENT
: The address of theTestRecipient
contract on the destination chain, left padded to abytes32
. In our case:0x00000000000000000000000036FdA966CfffF8a9Cdc814f546db0e6378bFef35
Using Metamask
Using Cast
- 2.Under the
Contract
tab, find theWrite as Proxy
button. - 3.Click on the
Connect to Web3
button to connect your Wallet (i.e. Metamask). Make sure that you are on the correct network. - 4.Expand the
dispatch
box. - 5.For destination domain, enter
$DESTINATION_DOMAIN
. You can find some here, or you could use137
to send to Mainnet Polygon. - 6.For the recipient address, enter
$RECIPIENT
. Remember to make sure to zero-pad this to abytes32
if you are using your own address. Alternatively, you can use0x00000000000000000000000036FdA966CfffF8a9Cdc814f546db0e6378bFef35
(our test recipient address). - 7.For the message body, enter whatever you like! A string-to-hex converter website can help you write your message if you want to send a human-readable message. In the example below, we sent the "Hello World" string as
0x48656c6c6f20576f726c64
- 8.Submit the transaction via your wallet/Metamask

How to send an interchain message using Etherscan + Metamask
You can call
Mailbox.dispatch()
directly using cast
. Make sure that you have a valid RPC URL for the origin chain and a private key with which you can pay for gas.cast send $MAILBOX_ADDRESS "dispatch(uint32,bytes32,bytes)" $DESTINATION_DOMAIN $RECIPIENT $(cast --from-utf8 "your message") --rpc-url $RPC_URL
--private-key $PRIVATE_KEY
Next, you must pay for interchain gas in the following section.
If you view the transaction on a block explorer, you should be able to see the
Dispatch
event. You can see an example message sending transaction here.For a message to be delivered by an off-chain relayer, the message must pay interchain gas on the origin chain to cover the destination chain transaction costs. This is done by calling the
payForGas
function of an "Interchain Gas Paymaster" contract, which lets you pay a relayer to deliver a message on your behalf.This
payForGas
call would typically be done by a smart contract that would first dispatch the message and immediately pay for gas, but because we dispatched the message from an externally owned account (EOA), we need to pay for gas with a separate transaction.$IGP_ADDRESS
: The address of the DefaultIsmInterchainGasPaymaster contract address on the origin chain.$DESTINATION_DOMAIN
: The domain ID of the destination chain. Domain IDs can be found here. This should be the same destination domain you used when sending the message.$MESSAGE_ID
: This is a0x
-prefixed hexadecimal 32-byte identifier of your message that you just dispatched.- This is returned by the
Mailbox.dispatch
function, but for our purposes this can most easily be found in a block explorer. Navigate to the transaction where you previously calledMailbox.dispatch
in a block explorer, open the "Logs" tab, and find theDispatchId
log. The "Topic 1" is your message ID. Use the dropdown to select "Hex", and use this value. For example:Finding the message ID from theDispatchId
log
Using Metamask
Using Cast
- 2.Under the
Contract
tab, selectRead Contract
. - 3.Expand the
quoteGasPayment
function. - 4.For destination domain, enter
$DESTINATION_DOMAIN
. - 5.For gas amount, enter
100000
. - 6.Click
Query
and make note of the amount returned as$GAS_PAYMENT_QUOTE
. For example, at the time of writing, the quote is1
wei.
- 1.Still on the
DefaultIsmInterchainGasPaymaster
contract page on Etherscan, selectWrite Contract
. - 2.Click on the
Connect to Web3
button to connect your Wallet (i.e. Metamask). Make sure that you are on the correct network. - 3.Expand the
payForGas
function. - 4.For the payable amount, Etherscan expects an amount quoted in ether, while our $GAS_PAYMENT_QUOTE is in wei. To convert from wei to ether, input the amount
$GAS_PAYMENT_QUOTE
, which is in wei, into https://eth-converter.com/ and copy the ether amount. Use this ether amount as the payable amount. - 5.For the message ID, input your
$MESSAGE_ID
. - 6.For the destination domain, input your
$DESTINATION_DOMAIN
. - 7.For the gas amount, input
100000
. - 8.For the refund address, input the address of the account you will sign the transaction with. This will receive a potential refund if you overpay for interchain gas.
- 9.Click "Write" and submit the transaction via your wallet/Metamask.

We'll be paying for 100,000 gas to be used by the TestRecipient's message handler.
First, get a quote for how much your gas payment will cost, and save this in an environment variable called
$GAS_PAYMENT_QUOTE
:cast call $IGP_ADDRESS "quoteGasPayment(uint32,uint256)" $DESTINATION_DOMAIN 100000 --rpc-url $RPC_URL
Now, we can call
payGasFor
, and we supply the gas payment quote as value in the transaction. The final parameter, $MY_ADDRESS
, is the address of the account whose private key you're signing with. This address will be refunded any overpayment.cast send $IGP_ADDRESS "payForGas(bytes32,uint32,uint256,address)" $MESSAGE_ID $DESTINATION_DOMAIN 100000 $MY_ADDRESS --rpc-url $RPC_URL
--private-key $PRIVATE_KEY --value $GAS_PAYMENT_QUOTE
After the transaction that sent your message is finalized, you should be able to see a corresponding transaction delivering your message to the
TestRecipient
contract on the destination chain. You can watch for this transaction on Hyperlane's Message Explorer by entering the transaction hash or the sender/recipient address in the input field.
You can see an example message delivery transaction here.
Test "Hello World" message sent from Ethereum to Polygon, shown in the Hyperlane Message Explorer
Last modified 12d ago