| 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.toml for shared tasks
- a contract-level
Makefile.toml in 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 invariants
services/ for orchestration and environment-aware composition
gateway/ for external module interaction and protocol I/O
queries/ for query string / payload builders
replies/ for reply handlers
axone-gov is the reference example for the richer layered shape.
Layer Boundaries
msg.rs defines the public contract surface.
contract.rs wires the AppContract entrypoints 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.rs should 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
DependencyCreation impl 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-design
api-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.json is 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, or from_state.
- Reuse canonical domain types rather than passing partially validated strings across layers.