name: cosmwasm-contract description: Axone contract structure and Abstract SDK patterns. Use when scaffolding or refactoring contracts, deciding layer boundaries, wiring AppContract entrypoints, or adding module metadata and replies. license: BSD-3-Clause metadata: author: axone.xyz version: "1.0"
CosmWasm Contract Structure
Companion Skills
Use rust-contract-domain-modeling for invariant-heavy domain design, api-design for message surfaces, api-doc-comments for schema-facing documentation, rust-testing for tests, and rust-quality-gates for validation gates.
Repository Structure
The repository has:
- a workspace-level
Makefile.tomlfor shared tasks - a contract-level
Makefile.tomlin each contract for local helpers - one directory per contract under
contracts/
Minimal Contract Skeleton
Start from this minimal shape:
contracts/<contract-name>/
├── Cargo.toml
├── Makefile.toml
├── README.md
├── metadata.json
├── src/
│ ├── lib.rs
│ ├── contract.rs
│ ├── msg.rs
│ ├── state.rs
│ ├── error.rs
│ ├── handlers/
│ │ ├── mod.rs
│ │ ├── instantiate.rs
│ │ ├── execute.rs
│ │ ├── query.rs
│ │ └── migrate.rs
│ └── bin/
│ ├── schema.rs
│ ├── publish.rs
│ └── install.rs
└── tests/
└── integration.rs
Add extra layers only when they clarify boundaries.
Optional Layers Already Used In This Repo
Current repository layers include:
domain/for explicit business concepts and invariantsservices/for orchestration and environment-aware compositiongateway/for external module interaction and protocol I/Oqueries/for query string / payload buildersreplies/for reply handlers
axone-gov is the reference example for the richer layered shape.
Layer Boundaries
msg.rsdefines the public contract surface.contract.rswires theAppContractentrypoints and module metadata.handlers/should stay thin: decode messages, call domain/services, build responses.domain/should own invariants and canonical representations.services/should coordinate enriched flows or external calls without becoming a second handler layer.gateway/should isolate external query / module plumbing.state.rsshould persist and reconstruct values, not silently redefine business rules.
lib.rs Pattern
Keep module identity constants explicit:
pub const AXONE_NAMESPACE: &str = "axone";
pub const CONTRACT_NAME: &str = "my-contract";
pub const CONTRACT_ID: &str = const_format::concatcp!(AXONE_NAMESPACE, ":", CONTRACT_NAME);
pub const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
contract.rs Pattern
The baseline AppContract wiring looks like this:
use abstract_app::AppContract;
pub type MyContract = AppContract<
MyContractError,
MyContractInstantiateMsg,
MyContractExecuteMsg,
MyContractQueryMsg,
MyContractMigrateMsg,
>;
const APP: MyContract = MyContract::new(CONTRACT_ID, APP_VERSION, None)
.with_instantiate(handlers::instantiate_handler)
.with_execute(handlers::execute_handler)
.with_query(handlers::query_handler)
.with_migrate(handlers::migrate_handler)
.with_dependencies(&[]);
#[cfg(feature = "export")]
abstract_app::export_endpoints!(APP, MyContract);
abstract_app::cw_orch_interface!(APP, MyContract, MyContractInterface);
Repository-specific refinements:
- Use
Some(APP_METADATA_URL)when the contract publishes metadata from a tagged GitHub URL. - Add
.with_replies(...)when the contract has reply-driven flows. - Keep
.with_dependencies(&[])explicit unless real module dependencies exist. - Add the non-wasm
DependencyCreationimpl when the interface needs the standard installation path used in this repo.
Message Wiring
Use abstract_app::app_msg_types!(...) in msg.rs when following the repository's Abstract app pattern.
Keep message docs and response typing aligned with:
api-designapi-doc-comments
Error Design
Error enums should include the standard conversion layers used by the contract and then domain-specific errors.
Do not hide domain invariants in generic StdError messages if a dedicated error variant would make the failure explicit.
Replies and Metadata
Two patterns matter in this repository:
metadata.jsonis part of the contract deliverable and should stay aligned with the module identity.- reply handlers are normal when contract setup involves follow-up callbacks or submessage completion.
Treat both as first-class contract structure, not optional afterthoughts.
Construction Rules
- Put invariant checks close to domain object creation.
- Keep handler branches short; move validation-heavy logic out of handlers.
- Prefer explicit constructors such as
new,try_new, orfrom_state. - Reuse canonical domain types rather than passing partially validated strings across layers.