Skip to main content
This guide uses the General Message Passing (GMP) app to call a contract on another chain. You’ll send the call from a source chain and execute it on the destination chain from an account derived from the sender.

Before you begin

The commands on this page need:
  • Foundry v1.5.1 or later, for forge and cast
  • jq installed
  • Git installed
Follow the tutorial to set up a deployment with a GMP app, a client, and a running relayer. Once you have a live connection and a running relayer, you’ll need the following values from each chain. Run the commands in this guide from the ibc/cli directory:
Print the private key you imported from the tutorial:
Export the values from the outputs above:

1. Deploy a contract to call

A GMP call arrives on the destination as a contract call, carrying the packet’s payload as its call data. Every GMP call executes through an account contract that belongs to the sender, so the target reads that account’s address as msg.sender. Create a Foundry project in the ibc/cli directory:
  1. Write a receiver that stores a value it is passed and the caller. Save it in the project as gmp-guide/src/Remote.sol:
  1. Deploy the contract on the destination chain:
  1. Keep the address it printed:

2. Send the call

Sending is a single call to sendCall on the source chain’s GMP contract:
The four steps below build one packet on chain A. It carries a call to set(42), addressed to the Remote contract you deployed on chain B.
  1. Encode the call to be made as the payload:
  1. Read the source chain’s clock and pick a timeout an hour out:
  1. Dry-run the send:
The number it returns is the sequence the packet would get.
  1. Send the source transaction, keeping the hash so you can relay it:

3. Relay the packet

The relayer will pick up the packet automatically and relay it to the destination chain. The command below reads the tutorial’s relayer; add --config <file> if yours runs from a different one, as it does after Run a standalone relayer. You can watch the transaction settle on the destination. This takes about a minute:
Success looks like this:

Verify the call landed

Now verify the state changed on the destination contract:
Then read the caller:
That is your account on the destination chain, derived from the destination chain’s client identifier, your sender string, and the salt. This can also be computed ahead of time by calling the destination’s GMP contract:
The mapping works in reverse too, which is how a receiving contract identifies who called it:
The account is a contract that is deployed on the first inbound call for that identifier.

Contract acknowledgement callbacks

When sending from a contract, the sender can receive the acknowledgement by implementing two callback functions:
Both structs carry the two client identifiers, the sequence, the original payload, and the relayer’s address. The acknowledgement path adds the raw acknowledgement bytes. Those decode as a GMPAcknowledgement when success is true, and carry a fixed error constant when it is not.
  • GMP only calls back if your contract advertises that it can receive callbacks. You can do that by inheriting IBCCallbackReceiver.
  • Each sendCall returns a sequence number. Save it if you need to match an acknowledgement to the call that caused it.