Overview
ICS27-GMP (also calledics27-2) is the IBC v2 protocol for general cross-chain contract execution. A sender on one chain can trigger a function call on a destination chain. The destination chain executes the call through a deterministically derived account.
Specification: ICS-027-GMP
Implementations:
- Cosmos side (Go):
ibc-go/modules/apps/27-gmp - EVM side (Solidity):
solidity-ibc-eureka/contracts/ICS27GMP.sol
gmpport.
How it works
- A sender calls
sendCall(EVM) or submitsMsgSendCall(Cosmos) with areceiveraddress, apayload, and asalt. - GMP constructs a
GMPPacketDatapacket with the sender’s address, the receiver, the salt, and the payload, then submits it via the IBC router. - On the destination chain,
onRecvPacketderives or creates a GMP account for(destinationClientId, sender, salt). This account is the on-chain identity that executes the call. - The GMP account calls
receiverwithpayload. - The return value is returned to the sender as an IBC acknowledgement.
(clientId, sender, salt), the account address is always the same and can be computed before the packet is sent.
Data structures
GMPPacketData
This is the IBC packet payload. It is constructed by GMP and carried over IBC.
In the Solidity implementation (IICS27GMPMsgs.sol):
packet.proto):
AccountIdentifier
Uniquely identifies a GMP account on the destination chain. The derived account address is a deterministic function of these three values.
Solidity (IICS27GMPMsgs.sol):
account.proto):
Sending a GMP packet
EVM: sendCall
The primary entry point on the EVM side is ICS27GMP.sendCall:
SendCallMsg is (IICS27GMPMsgs.sol):
sendCall captures msg.sender as an EIP-55 checksummed string and builds the packet:
ICS26Router.sendPacket with:
sourcePort = destPort = "gmpport"version = "ics27-2"encoding = "application/x-solidity-abi"
Cosmos: MsgSendCall
The Cosmos SDK message (tx.proto):
encoding is empty, it defaults to application/x-solidity-abi (msg_server.go).
Validation limits (msgs.go):
GMP account derivation
Each(clientId, sender, salt) maps to a single account on the destination chain. The account is created on first packet receive; however, its address can be computed before any packet is sent.
EVM
The account is a BeaconProxy deployed with Create2 (ICS27GMP.sol):
clientId used here is the destination client ID set in onRecvPacket.
Cosmos
The account address is derived deterministically from theAccountIdentifier fields using a length-prefixed key built from clientId, sender, and salt, then passed to address.Module("gmp-accounts", key). The implementation is in account.go.
To query the derived address on a running chain:
Payload encoding
Thepayload field is opaque bytes interpreted by the destination chain runtime.
The following example is from the Cosmos IFT demo tutorial, which uses GMP for transfers between EVM and Cosmos chains. For EVM → Cosmos IFT transfers,
CosmosIFTSendCallConstructor builds the payload as a protojson-encoded CosmosTx containing a MsgIFTMint (CosmosIFTSendCallConstructor.sol):
signer field is the GMP account address (ICA) on the Cosmos chain, which must match the account that onRecvPacket will derive. The EVM sender must be EIP-55 checksummed when querying the ICA.
Supported encodings
Defined inpacket.go (application/x-solidity-abi is also a constant in ICS27Lib.sol):
Acknowledgements
onRecvPacket returns the raw return value of the destination call wrapped in a GMPAcknowledgement:
onAcknowledgementPacket and onTimeoutPacket callbacks via the ICS-30 callbacks middleware.
receiver field
receiver is the address of the contract to call on the destination chain. On EVM, onRecvPacket parses it as a Solidity address and calls it via the GMP account:
Demo: IFT transfers using GMP
The IBC demo uses GMP for both directions of IFT token transfers. The demo runs in Docker and uses shell helpers (cast_in_net, run_in) to execute commands inside containers. The commands below show the underlying operations for illustration.
EVM → Cosmos
In the demo,IFTOwnable.iftTransfer burns tokens on the EVM side and sends a GMP packet to mint them on Cosmos. The call chain is:
iftTransfer(clientId, receiver, amount, timeoutTimestamp)calls the internal_iftTransfer_iftTransferburns the tokens, then callsCosmosIFTSendCallConstructor.constructMintCallto build the payload, then callsICS27GMP.sendCallwith:sourceClient: the EVM client IDreceiver: the Cosmos IFT module account address (thecounterpartyIFTAddressregistered inregisterIFTBridge)salt: empty for this demopayload: protojson-encodedCosmosTxcontainingMsgIFTMint
- On the Cosmos side, GMP derives the account for
(destClientId, iftContractAddress, ""), executes theMsgIFTMintmessage in the payload, and mints tokens to the receiver.
lib/demo.sh):
Cosmos → EVM
tx ift transfer sends a MsgSendCall with an ABI-encoded iftMint(address, uint256) payload. The MsgSendCall.sender is the IFT module account address. On the EVM side, GMP derives the account for (destClientId, iftModuleAddress, "") and calls IFTOwnable.iftMint through it. iftMint verifies that the calling GMP account’s sender field matches the registered counterparty IFT address before minting.
The demo triggers this with (lib/demo.sh):
Integrating GMP
Cosmos
An example of the full wiring of the GMP module is in sandbox-ledger PR #1, which adds GMP to an existing Cosmos SDK chain. The steps are:- Add module account permissions in
maccPerms:
- Register the store key:
- Add the keeper to your app struct and initialize it:
- Register the IBC v2 route:
- Register in the module manager:
gmptypes.ModuleName to SetOrderBeginBlockers, SetOrderEndBlockers, and SetOrderInitGenesis.
EVM chain
This deployment is taken from the IBC demo. GMP on the EVM side is two deployment steps. The full script isMinimalDeploy.s.sol.
- The
ICS27AccountandICS27GMPlogic contracts are deployed, then GMP is wrapped in an ERC1967 proxy:
ICS27Account is the logic contract for GMP’s beacon proxy accounts. In the demo, ICS27GMP is wrapped in an ERC1967 proxy and initialized with the router, account logic, and access manager.
- The
ICS26Routeris registered with the GMP contract:
gmpport to ICS27GMP.onRecvPacket.