To build a MsgCreateClient
, we need client_state
, consensus_state
and signer
. We need to create a solo-machine
client on IBC enabled chain and a tendermint client on IBC enabled solo-machine.
-
To create a solo-machine client on IBC enabled chain, we first create
consensus_state
:let consensus_state = ConsensusState { public_key: "can be obtained from mnemonic provided by user", diversifier: "provided by user (can have a default value)", timestamp: "current timestamp" };
Then, we create
client_state
:let client_state = ClientState { sequence: 1, frozen_sequence: 0, consensus_state, allow_update_after_proposal: false, };
Lastly,
signer
can be obtained from mnemonic provided by user (mnemonic.account_address()
).Finally, after creating
MsgCreateClient
from above values, build a raw transaction usingTransactionBuilder
and send it to tendermint using JSON RPC (broadcast_tx_commit
).client_id
can be extracted from response ofbroadcast_tx_commit
: code. -
To create a tendermint client on IBC enabled solo-machine, we first create
client_state
:let client_state = ClientState { chain_id: "chain id of ibc enabled chain (provided by user)", trust_level: "provide by user (default value = 1/3)" trusting_period: "provided by user (default value = 336 * 60 * 60 = 336 hours)" unbonding_period: "unbonding period of ibc enabled chain (can be obtained from grpc query, see notes below)", max_clock_drift: "provide by user (default value = 3000 millis)", frozen_height: 0, latest_height: "latest height of ibc enabled chain (can be obtained from rpc query, see notes below)", proof_specs: "cosmos sdk specs (see notes below)", upgrade_path: vec!["upgrade".to_string(), "upgradedIBCState".to_string()], allow_update_after_expiry: false, allow_update_after_misbehaviour: false, };
Note:
unbonding_period
: grpc query, codelatest_height
: rpc query, codeproof_specs
: code
Then we create
consensus_state
(needs tendermint light client): code, code, code, codeLastly,
signer
can be obtained from mnemonic provided by user (mnemonic.account_address()
).Finally, pass these values to
IbcTxHandler
of solo-machine. -
After
IbcTxHandler
on solo-machine receivesclient_state
andconsensus_state
: code- Generate a
client_id
- Store
client_state
inprivate_store
- Store
consensus_state
inprovable_store
Implementation note:
For solo machine, we do not need two different stores, i.e.,
private_store
andprovable_store
. Current implementation only uses one store (non-provable). - Generate a
To establish a connection between IBC enabled chain and solo-machine, we need to send multiple messages to both, IBC enabled chain and solo-machine (specs). In a nutshell:
- Send
MsgConnectionOpenInit
to IBC enabled chain - Send
MsgConnectionOpenTry
to IBC enabled solo-machine - Send
MsgConnectionOpenAck
to IBC enabled chain - Send
MsgConnectionOpenConfirm
to IBC enabled solo-machine
To establish connection on both sides:
-
MsgConnectionOpenInit
: codeFirst, create
MsgConnectionOpenInit
:let msg = MsgConnectionOpenInit { client_id: "client id of solo-machine client on ibc enabled chain (client id returned from 1st step of client creation)", counterparty: Counterparty { client_id: "client id of tendermint client on solo machine (client id returned from 2nd step of client creation)", connection_id: "".to_string(), prefix: MerklePrefix { key_prefix: "ibc".to_string(), // this should be obtained from a real chain query (ok for now) } }, version: Version { identifier: "1".to_string(), features: vec!["ORDER_ORDERED".to_string(), "ORDER_UNORDERED".to_string()], }, delay_period: 0, signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())" };
Next, build a raw transaction using
TransactionBuilder
and send it to tendermint using JSON RPC (broadcast_tx_commit
).connection_id
can be extracted from response ofbroadcast_tx_commit
: code -
MsgConnectionOpenTry
:First, create
MsgConnectionOpenTry
:let msg = MsgConnectionOpenTry { client_id: "client id of tendermint client on solo machine (client id returned from 2nd step of client creation)", previous_connection_id: "".to_string(), client_state: "client state of solo-machine client stored on ibc-enabled chain (obtained by rpc query, see notes below)", counterparty: Counterparty { client_id: "client id of solo-machine client on ibc enabled chain (client id returned from 1st step of client creation)", connection_id: "connection id of solo machine on ibc enabled chain (connection id returned from `MsgConnectionOpenInit`)", prefix: MerklePrefix { key_prefix: "ibc".to_string(), // this should be obtained from a real chain query (ok for now) }, }, delay_period: 0, counterparty_versions: vec![Version { identifier: "1".to_string(), features: vec!["ORDER_ORDERED".to_string(), "ORDER_UNORDERED".to_string()], }], proof_height: "block height for which the proofs were queried (obtained by rpc query, see notes below)", proof_init: "obtained by rpc query, see notes below", proof_client: "obtained by rpc query, see notes below", proof_consensus: "obtained by rpc query, see notes below", consensus_height: proof_consensus.height(), signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
client_state
,proof_init
,client_proof
,consensus_proof
andproof_height
: code
Next, pass all the above values to
IbcTxHandler
of solo-machine.Important:
Before sending
MsgConnectionOpenTry
toIbcTxHandler
, we need to update tendermint client on solo-machine to the target height (proof_height
) usingMsgUpdateClient
. codeAfter
IbcTxHandler
receivesMsgConnectionOpenTry
:- Generate a new
connection_id
(if there is aprevious_connection_id
, we need to do some extra step which are not done in current implementation) - Fetch current
block_height
of solo machine (current_block_height
) and return error ifconsensus_height
is greater than or equal tocurrent_block_height
.
-
MsgConnectionOpenAck
:First, create
MsgConnectionOpenAck
:let msg = MsgConnectionOpenAck { connection_id: "connection id of solo machine client on ibc enabled chain (connection id returned from `MsgConnectionOpenInit`)", counterparty_connection_id: "connection id of tendermint client on ibc enabled solo machine (connection id returned for `MsgConnectionOpenTry` from `IbcTxHandler`)", version: Version { identifier: "1".to_string(), features: vec!["ORDER_ORDERED".to_string(), "ORDER_UNORDERED".to_string()], }, client_state: "client state of ibc enabled chain stored on solo machine (can be obtained from `IbcQueryHandler`)" proof_height: "block height of solo machine for which the proofs were constructed (see notes below)", proof_try: "see notes below", proof_client: "see notes below", proof_consensus: "see notes below", consensus_height: "latest height of ibc enabled chain's consensus state stored on solo machine", signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
proof_try
: Signature obtained by signingSignBytes
withsigning_key
obtained fromConnectionStateData
. proof verification code, codeproof_client
: Signature obtained by signingSignBytes
withsigning_key
obtained fromClientStateData
. proof verification codeproof_consensus
: Signature obtained by signingSignBytes
withsigning_key
obtained fromConsensusStateData
. proof verification code
Next, build a raw transaction using
TransactionBuilder
and send it to tendermint using JSON RPC (broadcast_tx_commit
).Important:
Before sending
MsgConnectionOpenAck
to IBC enabled chain, we need to update solo-machine client on IBC enabled chain to the target height (proof_height
) usingMsgUpdateClient
. code -
MsgConnectionOpenConfirm
:First, create
MsgConnectionOpenConfirm
:let msg = MsgConnectionOpenConfirm { connection_id: "connection id of tendermint client on ibc enabled solo-machine", proof_ack: "obtained by rpc query, see notes below", proof_height: "block height for which the proofs were queried (obtained by rpc query, see notes below)", signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
proof_ack
andproof_height
: Refer to the same code to generate proofs as inMsgConnectionOpenTry
.
Next, pass all the above values to
IbcTxHandler
of solo-machine.Important:
Before sending
MsgConnectionOpenTry
toIbcTxHandler
, we need to update tendermint client on solo-machine to the target height (proof_height
) usingMsgUpdateClient
. code
To create a channel between IBC enabled chain and solo-machine, we need to send multiple messages to both, IBC enabled chain and solo-machine (specs). In a nutshell:
- Send
MsgChannelOpenInit
to IBC enabled chain - Send
MsgChannelOpenTry
to IBC enabled solo-machine - Send
MsgChannelOpenAck
to IBC enabled chain - Send
MsgChannelOpenConfirm
to IBC enabled solo-machine
To create a channel on both sides:
-
MsgChannelOpenInit
:First, create
MsgChannelOpenInit
:let msg = MsgChannelOpenInit { port_id: "port id of channel on ibc enabled chain (provided by user, autogenerate?, default value = transfer)", channel: Channel { state: Init, ordering: "provided by user (default value = Unordered)", counterparty: Counterparty { port_id: "port id of channel on ibc enabled solo machine (provided by user, autogenerate?)", channel_id: "".to_string(), }, connection_hops: vec!["connection id of solo machine on ibc enabled chain (connection id returned from `MsgConnectionOpenInit`)"], version: "can be fetched from query (currently not possible, default value = 'ics20-1', see notes below)" }, signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
port_id
can be provided by user andversion
can be fetched from grpc query. But, currently, it is not possible. So, it is best to hardcode the values for now. value refNext, build a raw transaction using
TransactionBuilder
and send it to tendermint using JSON RPC (broadcast_tx_commit
).channel_id
can be extracted from response ofbroadcast_tx_commit
: sample attribute extraction code, event structure -
MsgChannelOpenTry
:First, create
MsgChannelOpenTry
:let msg = MsgChannelOpenTry { port_id: "port id of channel on ibc enabled solo machine (provided by user, autogenerate?, default value = transfer)", previous_channel_id: "".to_string(), channel: Channel { state: TryOpen, ordering: "provided by user (default value = Unordered)", counterparty: Counterparty { port_id: "port id of channel on ibc enabled solo machine (provided by user, autogenerate?)", channel_id: "channel id of solo machine on ibc enabled chain (channel id returned from `MsgChannelOpenInit`)" }, connection_hops: vec!["connection id of tendermint client on ibc enabled solo-machine (connection id returned from `MsgConnectionOpenTry`)"], version: "can be fetched from `IbcQueryHandler` (default value = 'ics20-1', see notes below)", }, counterparty_version: "can be fetched from query (currently not possible, default value = 'ics20-1', see notes below)", proof_init: "obtained by rpc query, see notes below", proof_height: "block height for which the proofs were queried (obtained by rpc query, see notes below)", signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
Next, pass all the above values to
IbcTxHandler
of solo-machine.Important:
Before sending
MsgChannelOpenTry
toIbcTxHandler
, we need to update tendermint client on solo-machine to the target height (proof_height
) usingMsgUpdateClient
. code -
MsgChannelOpenAck
First, create
MsgChannelOpenAck
:let msg = MsgChannelOpenAck { port_id: "port id of channel on ibc enabled chain (provided by user, autogenerate?, default value = transfer)", channel_id: "channel id of solo machine on ibc enabled chain (channel id returned from `MsgChannelOpenInit`)", counterparty_channel_id: "channel id of tendermint client on ibc enabled solo machine (channel id returned for `MsgChannelOpenTry` from `IbcTxHandler`)", counterparty_version: "ics20-1".to_string(), proof_try: "see notes below", proof_height: "block height of solo machine for which the proofs were constructed (see notes below)", signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Note:
proof_try
: Signature obtained by signingSignBytes
withsigning_key
obtained fromChannelStateData
. proof verification code. code
Next, build a raw transaction using
TransactionBuilder
and send it to tendermint using JSON RPC (broadcast_tx_commit
).Important:
Before sending
MsgChannelOpenAck
to IBC enabled chain, we need to update solo-machine client on IBC enabled chain to the target height (proof_height
) usingMsgUpdateClient
. code -
MsgChannelOpenConfirm
First, create
MsgChannelOpenConfirm
:let msg = MsgChannelOpenConfirm { port_id: "port id of channel on ibc enabled solo machine (provided by user, autogenerate?, default value = transfer)", channel_id: "channel id of tendermint client on ibc enabled solo machine (channel id returned for `MsgChannelOpenTry` from `IbcTxHandler`)", proof_ack: "obtained by rpc query, see notes below", proof_height: "block height for which the proofs were queried (obtained by rpc query, see notes below)", signer: "can be obtained from mnemonic provided by user (mnemonic.account_address())", };
Next, pass all the above values to
IbcTxHandler
of solo-machine.Important:
Before sending
MsgChannelOpenConfirm
toIbcTxHandler
, we need to update tendermint client on solo-machine to the target height (proof_height
) usingMsgUpdateClient
. code