During cargo cosmfuzz build, CosmFuzz patches cosmwasm-std's MockApi::addr_validate so it returns Ok(Addr::unchecked(input)). This reduces address-validation noise during fuzzing.
By default, CosmFuzz uses the standard cw-multi-test framework. However, you can customize the generated harness to use alternative testing frameworks.
- Use enhanced testing frameworks with more features
- Integrate with existing test infrastructure
- Add custom mocking or simulation logic
- Test against specific chain behaviors
- sylvia - Framework with macros for contract interfaces and testing
- cw-orchestrator - Advanced testing and deployment framework
- mesh-testing - Osmosis's enhanced multi-test framework
- Custom forks of cw-multi-test with chain-specific features
After running cargo cosmfuzz build, the generated harness is at:
/tmp/cosmfuzz/{your-project}/src/main.rs
You can edit this file directly! CosmFuzz won't overwrite it on subsequent builds (unless you delete it).
// Instead of:
use cw_multi_test::{App, Executor};
// Use your custom framework:
use my_custom_framework::{CustomApp, CustomExecutor};
// Or use cw-orchestrator:
use cw_orch::{prelude::*, daemon::Daemon};
fn main() {
ziggy::fuzz!(|data: &[u8]| {
// Initialize with your custom framework
let mut app = CustomApp::new_with_custom_features();
// Your custom setup
app.enable_custom_module();
// Rest of fuzzing logic...
// Parse messages, execute, check invariants
});
}CosmFuzz automatically preserves InstantiateMsg customizations across rebuilds using regex extraction. When you edit the generated harness to customize initialization:
let cw20_init_msg = cw20_InstantiateMsg {
name: "Test Token".to_string(),
symbol: "TEST".to_string(),
decimals: 6,
initial_balances: vec![],
mint: None,
marketing: None,
};This customization will be preserved when you run cargo cosmfuzz build again (e.g., after adding new invariants).
-
Generate initial harness:
cargo cosmfuzz build
-
Customize the generated code:
# Edit the generated harness vim /tmp/cosmfuzz/your-project/src/main.rs # Update dependencies in generated Cargo.toml if needed vim /tmp/cosmfuzz/your-project/Cargo.toml
-
Rebuild and fuzz:
cd /tmp/cosmfuzz/your-project cargo ziggy build cargo ziggy fuzzOr use CosmFuzz commands:
cargo cosmfuzz build cargo cosmfuzz fuzz
-
Iterate: Make changes, rebuild, re-fuzz
For testing against specific chain features (IBC, custom modules, etc.):
// In your customized harness
use custom_chain_multi_test::ChainApp;
fn main() {
ziggy::fuzz!(|data: &[u8]| {
let mut app = ChainApp::new_with_ibc();
// Set up IBC channels
let channel = app.create_ibc_channel(...);
// Fuzz IBC packet handling
// ... your custom logic
});
}The default harness uses bincode and delimiter-based message parsing. You can customize this:
fn main() {
ziggy::fuzz!(|data: &[u8]| {
// Custom parsing logic
let messages = match parse_custom_format(data) {
Ok(msgs) => msgs,
Err(_) => return, // Invalid input, skip
};
// Execute messages...
});
}CosmFuzz attempts to detect the ExecuteMsg import by finding the #[entry_point] execute function and reading its message parameter type. If it cannot resolve the type (or finds multiple candidates), it falls back to importing ExecuteMsg from {contract_crate}::msg::ExecuteMsg and prints a warning during cargo cosmfuzz build.
Beyond auto-discovered invariants, you can add custom checks in the harness:
fn main() {
ziggy::fuzz!(|data: &[u8]| {
// ... execute messages ...
// Auto-discovered invariants
contract::cosmfuzz::invariant_balance_positive(&app, &contract_addr);
// Custom runtime checks
assert!(app.block_info().height > 0, "Block height should advance");
// Custom cross-contract checks
verify_protocol_solvency(&app, &token_addr, &vault_addr);
});
}- Keep invariant calls: Don't remove the auto-generated invariant checks unless you're replacing them
- Test your harness: Run it manually with
cargo runbefore fuzzing to ensure it works - Version control: Consider committing your customized harness to your repo
- Document changes: Add comments explaining your customizations
- Upstream improvements: If you create a useful pattern, consider contributing it back!
Future versions may support custom templates:
cargo cosmfuzz build --template ./my-harness-template.rsThis would allow you to define your own harness structure while keeping invariant discovery automatic.
use sylvia::cw_multi_test::IntoApp;
use cosmwasm_std::{Addr, coins};
fn main() {
ziggy::fuzz!(|data: &[u8]| {
// Create Sylvia app
let app = sylvia::cw_multi_test::App::default().into_app();
// Use Sylvia's contract interface
let contract = MyContract::new(app.clone());
// Parse and execute messages
// ... fuzzing logic ...
// Call invariants
// ... invariant checks ...
});
}