Synopsis
This standard document specifies packet data structure, state machine handling logic, and encoding details for the account management system over an IBC channel between separate chains.Motivation
ICS-27 Interchain Accounts outlines a cross-chain account management protocol built upon IBC. ICS-27 enabled chains can programmatically create accounts on other ICS-27 enabled chains & control these accounts via IBC transactions (instead of signing with a private key). Interchain accounts retain all of the capabilities of a normal account (i.e. stake, send, vote) but instead are managed by a separate chain via IBC in a way such that the owner account on the controller chain retains full control over any interchain account(s) it registers on host chain(s).Definitions
Host Chain: The chain where the interchain account is registered. The host chain listens for IBC packets from a controller chain which contain instructions (e.g. cosmos SDK messages) that the interchain account will execute.Controller Chain: The chain registering and controlling an account on a host chain. The controller chain sends IBC packets to the host chain to control the account.Interchain Account: An account on a host chain. An interchain account has all the capabilities of a normal account. However, rather than signing transactions with a private key, a controller chain will send IBC packets to the host chain which signals what transactions the interchain account must execute.Interchain Account Owner: An account on the controller chain. Every interchain account on a host chain has a respective owner account on the controller chain.
Desired properties
- Permissionless: An interchain account may be created by any actor without the approval of a third party (e.g. chain governance). Note: Individual implementations may implement their own permissioning scheme, however the protocol must not require permissioning from a trusted party to be secure.
- Fault isolation: A controller chain must not be able to control accounts registered by other controller chains. For example, in the case of a fork attack on a controller chain, only the interchain accounts registered by the forked chain will be vulnerable.
- The ordering of transactions sent to an interchain account on a host chain must be maintained. Transactions must be executed by an interchain account in the order in which they are sent by the controller chain.
- If a channel closes, the controller chain must be able to regain access to registered interchain accounts by simply opening a new channel.
- Each interchain account is owned by a single account on the controller chain. Only the owner account on the controller chain is authorized to control the interchain account. The controller chain is responsible for enforcing this logic.
- The controller chain must store the account address of any owned interchain accounts registered on host chains.
- A host chain must have the ability to limit interchain account functionality on its chain as necessary (e.g. a host chain can decide that interchain accounts registered on the host chain cannot take part in staking).
Technical specification
General design
A chain can utilize one or both parts of the interchain accounts protocol (controlling and hosting). A controller chain that registers accounts on other host chains (that support interchain accounts) does not necessarily have to allow other controller chains to register accounts on its chain, and vice versa. This specification defines the general way to register an interchain account and send tx bytes to be executed on behalf of the owner account. The host chain is responsible for deserializing and executing the tx bytes and the controller chain must know how the host chain will handle the tx bytes in advance of sending a packet, thus this must be negotiated during channel creation.Controller chain contract
RegisterInterchainAccount
RegisterInterchainAccount is the entry point to registering an interchain account.
It generates a new controller portID using the owner account address.
It will bind to the controller portID and
call 04-channel ChanOpenInit. An error is returned if the controller portID is already in use.
A ChannelOpenInit event is emitted which can be picked up by an offchain process such as a relayer.
The account will be registered during the OnChanOpenTry step on the host chain.
This function must be called after an OPEN connection is already established with the given connection identifier.
The caller must provide the complete channel version. This MUST include the ICA version with complete metadata and it MAY include
versions of other middleware that is wrapping ICA on both sides of the channel. Note this will require contextual information
on what middleware is enabled on either end of the channel. Thus it is recommended that an ICA-auth application construct the ICA
version automatically and allow for users to optionally enable additional middleware versioning.
SendTx
SendTx is used to send an IBC packet containing instructions (messages) to an interchain account on a host chain for a given interchain account owner.
Host chain contract
RegisterInterchainAccount
RegisterInterchainAccount is called on the OnChanOpenTry step during the channel creation handshake.
AuthenticateTx
AuthenticateTx is called before ExecuteTx.
AuthenticateTx checks that the signer of a particular message is the interchain account associated with the counterparty portID of the channel that the IBC packet was sent on.
ExecuteTx
Executes each message sent by the owner account on the controller chain.Utility functions
Register & controlling flows
Register account flow
To register an interchain account we require an off-chain process (relayer) to listen forChannelOpenInit events with the capability to finish a channel creation handshake on a given connection.
- The controller chain binds a new IBC port with the controller portID for a given interchain account owner address.
{owner-account-address} matching the bound port will be authorized to send IBC packets over channels created with the controller portID. It is up to each controller chain to enforce this port registration and access on the controller side.
- The controller chain emits an event signaling to open a new channel on this port given a connection.
- A relayer listening for
ChannelOpenInitevents will continue the channel creation handshake. - During the
OnChanOpenTrycallback on the host chain an interchain account will be registered and a mapping of the interchain account address to the owner account address will be stored in state (this is used for authenticating transactions on the host chain at execution time). - During the
OnChanOpenAckcallback on the controller chain a record of the interchain account address registered on the host chain duringOnChanOpenTryis set in state with a mapping from (controller portID, controller connectionID) -> interchain account address. See metadata negotiation section below for how to implement this. - During the
OnChanOpenAck&OnChanOpenConfirmcallbacks on the controller & host chains respectively, the active-channel for this interchain account/owner pair, is set in state.
Active channels
The controller and host chain must keep track of anactive-channel for each registered interchain account. The active-channel is set during the channel creation handshake process. This is a safety mechanism that allows a controller chain to regain access to an interchain account on a host chain in case of a channel closing.
An example of an active channel on the controller chain can look like this:
{owner-account-address}) and connectionID pair.
The controller and host chains must verify that any new channel maintains the same metadata as the previous active channel to ensure that the parameters of the interchain account remain the same even after replacing the active channel. The Address of the metadata should not be verified since it is expected to be empty at the INIT stage, and the host chain will regenerate the exact same address on TRY, because it is expected to generate the interchain account address deterministically from the controller portID and connectionID (both of which must remain the same).
Metadata negotiation
ICS-27 takes advantage of ICS-04 channel version negotiation to negotiate metadata and channel parameters during the channel handshake. The metadata will contain the encoding format along with the transaction type so that the counterparties can agree on the structure and encoding of the interchain transactions. The metadata sent from the host chain on the TRY step will also contain the interchain account address, so that it can be relayed to the controller chain. At the end of the channel handshake, both the controller and host chains will store a mapping of (controller chain portID, controller/host connectionID) to the newly registered interchain account address (account registration flow). ICS-04 allows for each channel version negotiation to be application-specific. In the case of interchain accounts, the channel version will be a string of a JSON struct containing all the relevant metadata intended to be relayed to the counterparty during the channel handshake step (see summary below). Combined with the one channel per interchain account approach, this method of metadata negotiation allows us to pass the address of the interchain account back to the controller chain and create a mapping from (controller portID, controller connection ID) -> interchain account address during theOnChanOpenAck callback. As outlined in the controlling flow, a controller chain will need to know the address of a registered interchain account in order to send transactions to the account on the host chain.
Metadata negotiation summary
interchain-account-address is the address of the interchain account registered on the host chain by the controller chain.
- INIT
- TRY
- ACK
Controlling flow
Once an interchain account is registered on the host chain a controller chain can begin sending instructions (messages) to the host chain to control the account.- The controller chain calls
SendTxand passes message(s) that will be executed on the host side by the associated interchain account (determined by the controller side port identifier)
-
The host chain upon receiving the IBC packet will call
DeserializeTx. -
The host chain will then call
AuthenticateTxandExecuteTxfor each message and return an acknowledgment containing a success or error.
GetInterchainAccountAddress(controllerPortId, hostConnectionId) to get the expected interchain account address for the current controller port and connection identifier. If the signer of this message does not match the expected account address then authentication will fail.
Packet Data
InterchainAccountPacketData contains an array of messages that an interchain account can execute and a memo string that is sent to the host chain as well as the packet type. ICS-27 version 1 has only one type EXECUTE_TX.
Custom logic
ICS-27 relies on ICS-30 middleware architecture to provide the option for application developers to apply custom logic on the success or fail of ICS-27 packets. Controller chains will wrapOnAcknowledgementPacket & OnTimeoutPacket to handle the success or fail cases for ICS-27 packets.
Port & channel setup
The interchain account module on a host chain must always bind to a port with the idicahost. Controller chains will bind to ports dynamically, as specified in the identifier format section.
The example below assumes a module is implementing the entire InterchainAccountModule interface. The setup function must be called exactly once when the module is created (perhaps when the blockchain itself is initialized) to bind to the appropriate port.
setup function has been called, channels can be created via the IBC routing module.
Channel lifecycle management
An interchain account module will accept new channels from any module on another machine, if and only if the channel initialization step is being invoked from the controller chain.Closing handshake
Upgrade handshake
Packet relay
onRecvPacket is called by the routing module when a packet addressed to this module has been received.
onAcknowledgePacket is called by the routing module when a packet sent by this module has been acknowledged.
OnRecvPacket callback should not be called, and in case it is called, it should simply return an error acknowledgement:
Identifier formats
These are the default formats that the port identifiers on each side of an interchain accounts channel. The controller portID must include the owner address so that when a message is sent to the controller module, the sender of the message can be verified against the portID before sending the ICA packet. The controller chain is responsible for proper access control to ensure that the sender of the ICA message has successfully authenticated before the message reaches the controller module. Controller Port Identifier: optional prefixicacontroller- + mandatory {owner-account-address}
Host Port Identifier: icahost
The icacontroller- prefix on the controller port identifier is optional and host chains must not enforce that the counterparty port identifier includes it. Controller chains may decide to include it and validate that it is present in their own port identifier.
Example Implementations
- Implementation of ICS 27 in Go can be found in ibc-go repository.