IBCv2Message passing

Message passing

Smart contracts can send IBCv2 (Inter-Blockchain Communication version 2) messages from all entry points except query. This allows for interoperability between different blockchains through structured message-passing mechanisms.

Send IBCv2 messages

This section demonstrates how a smart contract can send IBCv2 messages by including them in the response of an entry point (such as execute). It creates an Ibc2Msg::SendPacket message containing a payload, which includes custom data serialized into JSON. The payload also defines source and destination ports and client identifiers. The message is then returned in the contract’s Response to initiate the cross-chain communication.

#[cosmwasm_schema::cw_serde]
pub struct MyIbcMsg {
    pub msg: String
}
 
#[cosmwasm_schema::cw_serde]
pub struct ExecuteMsg;
 
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    _deps: DepsMut,
    env: Env,
    _info: MessageInfo,
    _msg: ExecuteMsg,
) -> StdResult<Response> {
    let msg = MyIbcMsg {
        msg: "Hello world!".to_owned()
    };
 
    let source_port = format!("wasm2{}", env.contract.address);
    let destination_port = "wasm2cosmos1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrs2zhgh2".to_owned();
    let new_payload = Ibc2Payload::new(
        source_port,
        destination_port,
        "V1".to_owned(),
        "application/json".to_owned(),
        Binary::new(to_json_vec(&msg)?),
    );
 
    let new_msg = Ibc2Msg::SendPacket {
        source_client: "blockchains_source_client".to_owned(),
        payloads: vec![new_payload],
        timeout: env.block.time.plus_minutes(5_u64),
    };
 
    Ok(Response::default()
        .add_message(new_msg))
}

Verify Messages Sent On Behalf Of The Contract

This section introduces a security check to ensure only the contract itself can send IBCv2 messages using its assigned port ID. It shows the implementation of the ibc2_packet_send entry point, which validates that the message signer matches the contract address. If not, the function returns an error, preventing unauthorized IBCv2 message emissions.

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn ibc2_packet_send(
    deps: DepsMut,
    _env: Env,
    msg: Ibc2PacketSendMsg,
) -> StdResult<IbcBasicResponse> {
    if msg.signer != _env.contract.address {
        return Err(StdError::generic_err("Only this contract can send messages from it's IBCv2 port ID"));
    }
    Ok(IbcBasicResponse::default())
}

Note: It is possible to design a contract in such a way that other contracts can send IBCv2 messages using its port ID.

Asynchronous Acknowledgements

To send a synchronous acknowledgement, devs can use the response of the receive entry point. This section explains how to handle asynchronous acknowledgements for IBCv2 messages. In some scenarios, it may not be possible to acknowledge a message immediately after processing it. In such cases, contracts can send acknowledgements asynchronously by responding with an Ibc2Msg::WriteAcknowledgement message. The provided example demonstrates how to write a success acknowledgement using the received packet sequence. This mechanism ensures that both the sender and receiver are properly informed about the successful processing of an IBCv2 message.

#[cosmwasm_schema::cw_serde]
pub struct MyIbcMsg {
    pub msg: String,
}
 
#[cosmwasm_schema::cw_serde]
pub struct ExecuteMsg {
    pub packet_sequence_to_ack: u64,
}
 
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    _deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: ExecuteMsg,
) -> StdResult<Response> {
    Ok(
        Response::default().add_message(cosmwasm_std::Ibc2Msg::WriteAcknowledgement {
            source_client: "blockchains_source_client".to_owned(),
            packet_sequence: msg.packet_sequence_to_ack,
            ack: IbcAcknowledgement::new(StdAck::success(b"Success")),
        }),
    )
}