| name | api-design |
| description | Best practices for designing CosmWasm smart contract APIs. Use when defining message types, designing execute/query interfaces, or optimizing API ergonomics. |
| license | BSD-3-Clause |
| metadata | {"author":"axone.xyz","version":"1.0"} |
CosmWasm API Design Best Practices
Core Principles
- Minimalism - Include only what's necessary; avoid bloated APIs
- Clarity - Names should be self-documenting
- Consistency - Follow established patterns across all contracts
- Documentation - Every public type and field must have doc comments
Message Type Patterns
InstantiateMsg
#[cosmwasm_schema::cw_serde]
#[derive(Default)]
pub struct MyContractInstantiateMsg {
#[serde(default)]
pub some_config: Option<String>,
}
Guidelines:
- Derive
Default when possible for easier testing
- Use
#[serde(default)] for optional fields
- Keep required fields minimal
- Document each field
ExecuteMsg
#[cosmwasm_schema::cw_serde]
#[derive(cw_orch::ExecuteFns)]
pub enum MyContractExecuteMsg {
UpdateConfig {
new_admin: Option<String>,
},
ProcessAction {
action_id: String,
amount: Uint128,
},
}
Guidelines:
- Use verb-based names (Update, Process, Create, Remove)
- Group related parameters in structs if >3 fields
- Document each variant AND each field
- Derive
ExecuteFns for cw-orch integration
QueryMsg
#[cosmwasm_schema::cw_serde]
#[derive(cw_orch::QueryFns, QueryResponses)]
pub enum MyContractQueryMsg {
#[returns(ConfigResponse)]
Config {},
#[returns(ItemResponse)]
Item {
id: String,
},
#[returns(ItemsResponse)]
Items {
start_after: Option<String>,
limit: Option<u32>,
},
}
Guidelines:
- Always include
#[returns(ResponseType)] attribute
- Use noun-based names for queries
- Include pagination for list queries (
start_after, limit)
- Derive
QueryFns and QueryResponses
Response Types
#[cosmwasm_schema::cw_serde]
pub struct ConfigResponse {
pub admin: Addr,
pub paused: bool,
}
#[cosmwasm_schema::cw_serde]
pub struct ItemsResponse {
pub items: Vec<ItemInfo>,
}
Guidelines:
- Response types should mirror what clients need
- Use specific types (Addr, Uint128) not strings
- Document all fields
Abstract SDK Integration
Use the app_msg_types! macro to generate wrapper types:
use crate::contract::MyContract;
use cosmwasm_schema::QueryResponses;
abstract_app::app_msg_types!(MyContract, MyContractExecuteMsg, MyContractQueryMsg);
Documentation Standards
Rust Doc Comments
Field Documentation
Every field must have a doc comment:
- Describe what the field represents
- Mention default values if applicable
- Note any constraints (min/max values, format)
Serde Patterns
Optional Fields with Defaults
#[serde(default)]
pub optional_field: Option<String>,
#[serde(default = "default_limit")]
pub limit: u32,
fn default_limit() -> u32 {
10
}
Flatten for Nested Configs
#[cosmwasm_schema::cw_serde]
pub struct InstantiateMsg {
#[serde(flatten)]
pub base_config: BaseConfig,
pub custom_field: String,
}
Rename for JSON Clarity
#[serde(rename = "owner")]
pub owner_addr: Addr,