This site requires Javascript to be enabled.

Events

In CosmWasm, Result<Response, ContractError> is the typical return type for entry point functions, where Response acts as a wrapper for Events in the Cosmos SDK. Events are crucial for emitting information from your contract that can be captured by external systems, such as block explorers, wallets, or other smart contracts.

Understanding the Response type

The Response type should be returned as the successful result of a contract entry point, such as instantiate or execute. While you can declare it as mutable and modify it throughout the function body, a more common pattern is to construct the Response object at the end of the function, after all computations have been successfully completed, and then return it.

In the examples that follow, the Response is wrapped by Ok since it is being returned as part of a function that returns the Result type, with Response representing the success branch.

The Query entry point is an exception, as it returns StdResult due to the Cosmos SDK interface requirements, focusing purely on data retrieval without event emission.

For an in-depth look at the Response struct, you can review the source code here.

Basic usage of Response

The simplest use of Response is as follows:

Ok(Response::default())

This is a typical scenario in instantiate functions when no additional message or event needs to be returned to the client. It returns a default Response object with no events or messages attached.

Adding attributes to Response

In most cases, especially when handling execute functions, a Response with attributes should be returned. Attributes are key-value pairs that provide additional context about the action being performed, and they are particularly useful for logging and debugging.

Here’s an example of how to construct a Response with multiple attributes:

let res = Response::new()    .add_attribute("action", "transfer")    .add_attribute("from", info.sender.to_string())    .add_attribute("to", recipient.to_string())    .add_attribute("amount", amount.to_string());Ok(res)

Breakdown

  1. Creating a New Response: A new Response object is created using Response::new().
  2. Adding Attributes: Several key-value pairs are added to the Response. These attributes describe the action performed ("transfer"), the sender of the transaction (info.sender), the recipient, and the amount transferred.
  3. Returning the Response: The Response is then wrapped in an Ok and returned, signaling that the function executed successfully.

Observing events

When you invoke your contract through a command-line interface (CLI) or other tooling, these attributes will be visible in the transaction logs (under "raw_log"). They are logged alongside other SDK events and can be used to track the actions performed by the contract.

It will look something like this:

{  "height": "12345",  "txhash": "A1B2C3D4E5F6G7H8I9J0K",  "raw_log": [    {      "msg_index": "0",      "events": [        {          "type": "transfer_event",          "attributes": [            {              "key": "action",              "value": "transfer"            },            {              "key": "from",              "value": "archway1...sender"            },            {              "key": "to",              "value": "archway1...recipient"            },            {              "key": "amount",              "value": "1000aarch"            }          ]        }      ]    }  ]}

Breakdown of the raw_log:

- **"msg_index**"**: Indicates the position of the message in the transaction (e.g., the first message in this case).
- **"type"**: The type of event emitted, here it's "transfer_event".
- **"attributes"**: The key-value pairs that describe the event. In this example:
    - **"action"**: Describes the action performed, which is "transfer".
    - **"from"**: Indicates the sender of the transfer.
    - **"to"**: Indicates the recipient of the transfer.
    - **"amount"**: The amount transferred.

Advanced usage: adding custom events

In addition to attributes, you can add custom events to the Response. This is done using the add_event method, which allows you to create more structured and meaningful events that other clients or contracts can interact with.

Here’s an example of how to add a custom event:

use cosmwasm_std::{Event, Response};let custom_event = Event::new("transfer_event")    .add_attribute("from", info.sender.to_string())    .add_attribute("to", recipient.to_string())    .add_attribute("amount", amount.to_string());let res = Response::new()    .add_event(custom_event);Ok(res)

Breakdown

  1. Creating a Custom Event: A new Event object is created with a custom type ("transfer_event"). Attributes are added to this event, similar to how they are added to a Response.
  2. Adding the Event to the Response: The custom event is added to the Response using the add_event method.
  3. Returning the Response: The Response with the custom event is returned, allowing other contracts or clients to process this event as needed.

Why use custom events?

Custom events are beneficial when you need to emit more structured information that might be used by other contracts or by external systems that listen for specific event types. They allow for better organization and retrieval of data related to your contract’s operations.

Best Practices

  • Consistent Naming: Use consistent naming conventions for your events and attributes to make them easily identifiable.
  • Security Considerations: Ensure that sensitive information is not exposed in event attributes, as these are public and can be accessed by anyone monitoring the blockchain.
  • Use Events for Key Actions: Emit events for key actions in your contract to provide transparency and auditability, making it easier to trace and understand the flow of operations.