Entry Point Function Generation

Contract execution and querying is so common that we felt the need to improve the method of calling them. To do this we created two macros: ExecuteFns and QueryFns. As their name implies they can be used to automatically generate functions for executing and querying your contract through the interface.

Execution

To get started, find the ExecuteMsg definition for your contract. In our case it’s located in counter/src/msg.rs. Then add the following line to your ExecuteMsg enum:

#[cw_serde]
#[cfg_attr(feature = "interface", derive(cw_orch::ExecuteFns))] // Function generation
/// Execute methods for counter
pub enum ExecuteMsg {
    /// Increment count by one
    Increment {},
    /// Reset count
    Reset {
        /// Count value after reset
        count: i32,
    },
}

Again we feature flag the function generation to prevent cw-orchestrator entering as a dependency when building your contract.

The functions are implemented as a trait named ExecuteMsgFns which is implemented on any interface that uses this ExecuteMsg as an entrypoint message.

Using the trait then becomes as simple as:

    // in integration_tests.rs
    // Reset
    use counter_contract::CounterExecuteMsgFns;
    contract.reset(0)?;

Query

Generating query functions is a similar process but has the added advantage of using the cosmwasm-schema return tags to detect the query’s return type. This allows for type-safe query functions!

#[cw_serde]
#[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] // Function generation
#[derive(QueryResponses)]
/// Query methods for counter
pub enum QueryMsg {
    /// GetCount returns the current count as a json-encoded number
    #[returns(GetCountResponse)]
    GetCount {},
}

// Custom response for the query
#[cw_serde]
/// Response from get_count query
pub struct GetCountResponse {
    /// Current count in the state
    pub count: i32,
}

Using it is just as simple as the execution functions:

    // in integration_tests.rs
    // Get the count.
    use counter_contract::CounterQueryMsgFns;
    let count1 = contract.get_count()?;

    // or query it manually
    let count2: GetCountResponse = contract.query(&QueryMsg::GetCount {})?;
    assert_eq!(count1.count, count2.count);

Just like the interface it can be beneficial to re-export the trait in your lib.rs or interface.rs file.

In the counter contract we re-export in lib.rs;

#[cfg(feature = "interface")]
pub use crate::msg::{ExecuteMsgFns as CounterExecuteMsgFns, QueryMsgFns as CounterQueryMsgFns};

Additional Remarks on QueryFns and ExecuteFns

The QueryFns and ExecuteFns derive macros generate traits that are implemented on any Contract structure (defined by the interface macro) that have the matching execute and query types. Because of the nature of rust traits, you need to import the traits in your application to use the simplifying syntax. Those traits are named ExecuteMsgFns and QueryMsgFns.

Any variant of the ExecuteMsg and QueryMsg that has a #[derive(ExecuteFns)] or #[derive(QueryFns)] will have a function implemented on the interface (e.g. CounterContract) through a trait. Here are the main things you need to know about the behavior of those macros:

  • The function created will have the snake_case name of the variant and will take the same arguments as the variant.
  • The arguments are ordered in alphabetical order to prevent attribute ordering from changing the function signature.
  • If coins need to be sent along with the message you can add #[payable] to the variant and the function will take a Vec<Coin> as the last argument.
  • The cw_orch::QueryFns macro needs your QueryMsg struct to have the cosmwasm_schema::QueryResponses macro implemented (this is good practice even outside of use with cw-orch).

Additional configuration

payable Attribute

Let’s see an example for executing a message (from a money market for instance).

    money_market.deposit_stable()?;

There’s a problem with the above function. The money market only knows how much you deposit into it by looking at the funds you send along with the transaction. Cw-orchestrator doesn’t ask for funds by default. However, to allow attaching funds to a transaction, you can add the #[payable] attribute on your enum variant like so:

    #[derive(ExecuteFns)]
    enum ExecuteMsg{
        UpdateConfig{
            config_field: String
        },
        #[payable]
        DepositStable{}
        ...
    }

Be defining this attribute, you can now use:

    use cosmwasm_std::coins;
    money_market.deposit_stable(&coins(456, "ujunox"))?;

fn_name Attribute

#[derive(cw_orch::ExecuteFns)] 
pub enum ExecuteMsg{
    Execute{
        msg: CosmoMsg
    }
}

The following command will error because the execute function is reserved for contract execution. This will not even compile actually.

// Doesn't compile
money_market.execute(message_to_execute_via_a_proxy)?;

This can happen in numerous cases actually, when using reserved keywords of cw-orch (or even rust). If this happens, you can use the fn_name attribute to rename a generated function.

#[derive(cw_orch::ExecuteFns)] 
pub enum ExecuteMsg{
    #[fn_name("proxy_execute")]
    Execute{
        msg: CosmoMsg
    }
}
// This works smoothly !
money_market.proxy_execute(message_to_execute_via_a_proxy)?;

This is also true for query functions.

impl_into Attribute

For nested messages (execute and query) you can add an impl_into attribute. This expects the enum to implement the Into trait for the provided type. This is extremely useful when working with generic messages:

use cw_orch::interface;
use cw_orch::prelude::*;

// An execute message that is generic.
#[cosmwasm_schema::cw_serde]
pub enum GenericExecuteMsg<T> {
    Generic(T),
    Nested(NestedMessageType),
}

// This is the message that will be used on our contract
type ExecuteMsg = GenericExecuteMsg<Foo>;
#[cosmwasm_schema::cw_serde]
#[derive(cw_orch::ExecuteFns)]
#[impl_into(ExecuteMsg)]
pub enum Foo {
    Bar { a: String },
}

impl From<Foo> for ExecuteMsg {
    fn from(msg: Foo) -> Self {
        ExecuteMsg::Generic(msg)
    }
}

#[cosmwasm_schema::cw_serde]
#[derive(cw_orch::ExecuteFns)]
#[impl_into(ExecuteMsg)]
pub enum NestedMessageType {
    Test { b: u64 },
}

impl From<NestedMessageType> for ExecuteMsg {
    fn from(msg: NestedMessageType) -> Self {
        ExecuteMsg::Nested(msg)
    }
}

#[interface(Empty, ExecuteMsg, Empty, Empty)]
struct Example<Chain>;

impl<Chain: CwEnv> Example<Chain> {
    pub fn test_macro(&self) {
        // function `bar` is available because of the `impl_into` attribute!
        self.bar("hello".to_string()).unwrap();

        // function `test` is available because of the `impl_into` attribute!
        self.test(65).unwrap();
    }
}

disable_fields_sorting Attribute

By default the ExecuteFns and QueryFns derived traits will sort the fields of each enum member. For instance,

#[cw_serde]
#[derive(cw_orch::ExecuteFns)]
pub enum ExecuteMsgOrdered {
    Test { b: u64, a: String },
}

will generate

pub fn bar(a: String, b: u64) -> ...{
   ...
} 

You see in this example that the fields of the bar function are sorted lexicographically. We decided to put this behavior as default to prevent potential errors when rearranging the order of enum fields. If you don’t want this behavior, you can disable it by using the disable_fields_sorting attribute. This is the resulting behavior:

#[cw_serde]
#[derive(cw_orch::ExecuteFns)]
#[disable_fields_sorting]
pub enum ExecuteMsg {
    Test { b: u64, a: String },
}

 
 pub fn bar(b: u64, a: String) -> ...{
    ...
 } 

NOTE: This behavior CAN be dangerous if your struct members have the same type. In that case, if you want to rearrange the order of the members inside the struct definition, you will have to be careful that you respect the orders in which you want to pass them.