contracts/[name]/
├── Cargo.toml
├── src/
│ ├── lib.rs # Entry point, exports
│ ├── contract.rs # Main logic (instantiate, execute, query)
│ ├── msg.rs # InstantiateMsg, ExecuteMsg, QueryMsg
│ ├── state.rs # State definitions (Item, Map)
│ └── error.rs # ContractError enum
├── schema/ # Generated JSON schemas
└── examples/
└── schema.rs # Schema generator
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::Uint128;
#[cw_serde]
pub struct InstantiateMsg {
pub admin: Option<String>,
}
#[cw_serde]
pub enum ExecuteMsg {
Burn {},
UpdateConfig { burn_rate: Uint128 },
}
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(StatsResponse)]
GetStats {},
#[returns(ProofResponse)]
GetProof { id: u64 },
}
#[cw_serde]
pub struct StatsResponse {
pub total_burned: Uint128,
pub proof_count: u64,
}
use cosmwasm_std::{Addr, Uint128};
use cw_storage_plus::{Item, Map};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct Config {
pub admin: Addr,
pub burn_rate: Uint128,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct BurnProof {
pub id: u64,
pub burner: Addr,
pub amount: Uint128,
pub timestamp: u64,
}
pub const CONFIG: Item<Config> = Item::new("config");
pub const PROOFS: Map<u64, BurnProof> = Map::new("proofs");
pub const PROOF_COUNT: Item<u64> = Item::new("proof_count");
use cosmwasm_std::{
entry_point, to_json_binary, Binary, Deps, DepsMut,
Env, MessageInfo, Response, StdResult, Uint128,
};
use cw2::set_contract_version;
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, StatsResponse};
use crate::state::{Config, CONFIG, PROOF_COUNT};
const CONTRACT_NAME: &str = "crates.io:proof-of-burn";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
#[entry_point]
pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let admin = msg.admin
.map(|a| deps.api.addr_validate(&a))
.transpose()?
.unwrap_or(info.sender);
CONFIG.save(deps.storage, &Config {
admin,
burn_rate: Uint128::from(10u128), // 10%
})?;
PROOF_COUNT.save(deps.storage, &0u64)?;
Ok(Response::new()
.add_attribute("action", "instantiate")
.add_attribute("admin", admin))
}
#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::Burn {} => execute_burn(deps, env, info),
ExecuteMsg::UpdateConfig { burn_rate } => {
execute_update_config(deps, info, burn_rate)
}
}
}
fn execute_burn(
deps: DepsMut,
env: Env,
info: MessageInfo,
) -> Result<Response, ContractError> {
// Get sent LUNC
let amount = info.funds
.iter()
.find(|c| c.denom == "uluna")
.map(|c| c.amount)
.unwrap_or(Uint128::zero());
if amount.is_zero() {
return Err(ContractError::NoFundsSent {});
}
// Create proof...
Ok(Response::new()
.add_attribute("action", "burn")
.add_attribute("amount", amount))
}
#[entry_point]
pub fn query(
deps: Deps,
_env: Env,
msg: QueryMsg,
) -> StdResult<Binary> {
match msg {
QueryMsg::GetStats {} => to_json_binary(&query_stats(deps)?),
QueryMsg::GetProof { id } => to_json_binary(&query_proof(deps, id)?),
}
}
fn query_stats(deps: Deps) -> StdResult<StatsResponse> {
let count = PROOF_COUNT.load(deps.storage)?;
// Calculate total...
Ok(StatsResponse {
total_burned: Uint128::zero(),
proof_count: count,
})
}
use cosmwasm_std::StdError;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),
#[error("Unauthorized")]
Unauthorized {},
#[error("No funds sent")]
NoFundsSent {},
#[error("Invalid denom: expected {expected}, got {got}")]
InvalidDenom { expected: String, got: String },
}