Skip to main content
Version: 1.0

Messages

MsgRegisterInterchainAccount

Attempts to register an interchain account by sending an IBC packet over an IBC connection.

message MsgRegisterInterchainAccount {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string from_address = 1;
string connection_id = 2 [ (gogoproto.moretags) = "yaml:\"connection_id\"" ];
string interchain_account_id = 3 [ (gogoproto.moretags) = "yaml:\"interchain_account_id\"" ];
}
  • from_address must be a smart contract address, otherwise the message will fail;
  • connection_id must be the identifier of a valid IBC connection, otherwise the message will fail;
  • interchain_account_id is used to generate the owner parameter for ICA's RegisterInterchainAccount() call, which is later used for port identifier generation (see below). Maximum allowed length of interchain_account_id is 47 characters.
IBC ports naming / Interchain Account address derivation

If a contract with the address neutron14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s5c2epq sends an MsgRegisterInterchainAccount with interchain_account_id set to hub/1, the generated ICA owner will look like neutron14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s5c2epq.hub/1, and the IBC port generated by the ICA app will be equal to icacontroller-neutron14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s5c2epq.hub/1.

ICA's remote address generation concatenates connection identifier and port identifier to use them as the derivation key for the new account:

// GenerateAddress returns an sdk.AccAddress derived using the provided module account address and connection and port identifiers.
// The sdk.AccAddress returned is a sub-address of the module account, using the host chain connection ID and controller chain's port ID as the derivation key
func GenerateAddress(moduleAccAddr sdk.AccAddress, connectionID, portID string) sdk.AccAddress {
return sdk.AccAddress(sdkaddress.Derive(moduleAccAddr, []byte(connectionID+portID)))
}

Note: your contract needs to implement the sudo() entrypoint on order to successfully process the IBC events associated with this message. You can find an example in the neutron-sdk repository.

Response

message MsgRegisterInterchainAccountResponse {}

IBC Events

type MessageOnChanOpenAck struct {
OpenAck OpenAckDetails `json:"open_ack"`
}

type OpenAckDetails struct {
PortID string `json:"port_id"`
ChannelID string `json:"channel_id"`
CounterpartyChannelId string `json:"counterparty_channel_id"`
CounterpartyVersion string `json:"counterparty_version"`
}

The data from an OnChanOpenAck event is passed to the contract using a Sudo() call. You can have a look at an example handler implementation in the neutron-sdk repository.

Note: you can find the interchain account address in the stored in the CounterpartyVersion field as part of metadata.

State modifications

None.

MsgSubmitTx

Attempts to execute a transaction on a remote chain.

message MsgSubmitTx {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string from_address = 1;
string interchain_account_id = 2;
string connection_id = 3;
repeated google.protobuf.Any msgs = 4;
string memo = 5;
uint64 timeout = 6;

neutron.feerefunder.Fee fee = 7 [ (gogoproto.nullable) = false ];
}
  • from_address must be a smart contract address, otherwise the message will fail;
  • interchain_account_id is identical to MsgRegisterInterchainAccount.interchain_account_id;
  • connection_id must be the identifier of a valid IBC connection, otherwise the message will fail;
  • msgs must contain not more than it is defined in the module params;
  • memo is the transaction memo;
  • timeout is a timeout in seconds after which the packet times out;
  • fee is a fee amount to refund relayer for ack and timeout messages submission.

Note: your smart-contract must have fee.ack_fee + fee.timeout_fee + fee.recv_fee coins on its balance, otherwise the message fails. See more info about fee refunding mechanism here.

Note: most networks reject memos longer than 256 bytes.

Note: your contract needs to implement the sudo() entrypoint on order to successfully process the IBC events associated with this message. You can find an example in the neutron-sdk repository.

Note: to see the currently available messages amount in a single MsgSubmitTx, query the module parameters:

neutrond query interchaintxs params

params:
msg_submit_tx_max_messages: "16"

Response

message MsgSubmitTxResponse {
uint64 sequence_id = 1;
string channel = 2;
}
  • sequence_id is a channel's sequence_id for outgoing ibc packet. Unique per a channel;
  • channel is the src channel name on neutron's side trasaction was submitted from;

IBC Events

type SudoMessageTimeout struct {
Timeout struct {
Request channeltypes.Packet `json:"request"`
} `json:"timeout"`
}

type SudoMessageResponse struct {
Response struct {
Request channeltypes.Packet `json:"request"`
Data []byte `json:"data"` // Message data
} `json:"response"`
}

type SudoMessageError struct {
Error struct {
Request channeltypes.Packet `json:"request"`
Details string `json:"details"`
} `json:"error"`
}

While trying to execute an interchain transaction, you can receive an IBC Timeout or an IBC Acknowledgement, and the latter can contain either a valid response or an error. These three types of transaction results are passed to the contract as distinct messages using a Sudo() call. You can have a look at an example handler implementation in the neutron-sdk repository.

You can more find info, recommendations and examples about how process acknowledgements here.

State modifications

None.