Introduction

StateSet Contracts enable autonomous, self-executing business agreements on the StateSet Commerce Network. Built on CosmWasm, these smart contracts power everything from automated order fulfillment to complex multi-party trade finance arrangements. This guide covers contract development, deployment, and integration.

What are StateSet Contracts?

StateSet Contracts are WebAssembly-based smart contracts that:

  • Execute Autonomously: Run without manual intervention when conditions are met
  • Ensure Trust: Immutable and transparent execution on blockchain
  • Enable Composability: Contracts can interact with each other
  • Support Complex Logic: Handle multi-party agreements and conditional flows

Prerequisites

Before developing StateSet Contracts:

  • Rust programming knowledge (basic to intermediate)
  • Familiarity with smart contract concepts
  • StateSet CLI installed (curl -L https://stateset.network/install | sh)
  • A StateSet Network account with testnet tokens

Getting Started

1

Install Development Tools

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install cargo-generate for templates
cargo install cargo-generate

# Install StateSet CLI
curl -L https://stateset.network/install | sh

# Verify installation
stateset version
2

Create Your First Contract

# Generate from template
cargo generate --git https://github.com/stateset/contract-template
cd my-first-contract

# Build the contract
cargo wasm

# Run tests
cargo test
3

Deploy to Testnet

# Store the contract code
stateset tx wasm store target/wasm32-unknown-unknown/release/my_contract.wasm \
  --from wallet \
  --chain-id stateset-testnet \
  --gas auto \
  --gas-adjustment 1.3

# Instantiate the contract
stateset tx wasm instantiate CODE_ID '{"admin":"stateset1..."}' \
  --from wallet \
  --label "my-contract" \
  --chain-id stateset-testnet

Core Contract Types

1. Order Management Contract

Automate order lifecycle from placement to fulfillment:

use cosmwasm_std::{
    entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
};
use cw2::set_contract_version;

const CONTRACT_NAME: &str = "stateset:order-manager";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Order {
    pub id: String,
    pub buyer: Addr,
    pub seller: Addr,
    pub items: Vec<OrderItem>,
    pub total: Uint128,
    pub status: OrderStatus,
    pub payment_status: PaymentStatus,
    pub created_at: Timestamp,
    pub fulfilled_at: Option<Timestamp>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum OrderStatus {
    Pending,
    Confirmed,
    Processing,
    Shipped,
    Delivered,
    Cancelled,
    Refunded,
}

#[entry_point]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::CreateOrder { items, shipping } => {
            create_order(deps, env, info, items, shipping)
        }
        ExecuteMsg::ConfirmPayment { order_id } => {
            confirm_payment(deps, env, info, order_id)
        }
        ExecuteMsg::ShipOrder { order_id, tracking } => {
            ship_order(deps, env, info, order_id, tracking)
        }
        ExecuteMsg::ConfirmDelivery { order_id } => {
            confirm_delivery(deps, env, info, order_id)
        }
        ExecuteMsg::InitiateRefund { order_id, reason } => {
            initiate_refund(deps, env, info, order_id, reason)
        }
    }
}

fn create_order(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    items: Vec<OrderItem>,
    shipping: ShippingInfo,
) -> Result<Response, ContractError> {
    // Validate items and calculate total
    let total = calculate_order_total(&items)?;
    
    // Generate unique order ID
    let order_id = generate_order_id(&env, &info.sender)?;
    
    // Create order object
    let order = Order {
        id: order_id.clone(),
        buyer: info.sender.clone(),
        seller: SELLER.load(deps.storage)?,
        items,
        total,
        status: OrderStatus::Pending,
        payment_status: PaymentStatus::Pending,
        created_at: env.block.time,
        fulfilled_at: None,
    };
    
    // Store order
    ORDERS.save(deps.storage, &order_id, &order)?;
    
    // Emit event
    Ok(Response::new()
        .add_attribute("action", "create_order")
        .add_attribute("order_id", order_id)
        .add_attribute("buyer", info.sender)
        .add_attribute("total", total))
}

2. Supply Chain Contract

Track products through the supply chain with full transparency:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct SupplyChainEvent {
    pub product_id: String,
    pub event_type: EventType,
    pub location: String,
    pub handler: Addr,
    pub timestamp: Timestamp,
    pub temperature: Option<i32>,
    pub humidity: Option<u32>,
    pub notes: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum EventType {
    Manufactured,
    QualityChecked,
    Packaged,
    ShippedFromFactory,
    ArrivedAtWarehouse,
    ShippedToRetailer,
    ReceivedByRetailer,
    SoldToCustomer,
}

pub fn track_product(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    product_id: String,
    event_type: EventType,
    location: String,
    metadata: Option<EventMetadata>,
) -> Result<Response, ContractError> {
    // Verify handler authorization
    verify_handler_authorization(&deps, &info.sender, &event_type)?;
    
    // Create supply chain event
    let event = SupplyChainEvent {
        product_id: product_id.clone(),
        event_type: event_type.clone(),
        location,
        handler: info.sender.clone(),
        timestamp: env.block.time,
        temperature: metadata.as_ref().and_then(|m| m.temperature),
        humidity: metadata.as_ref().and_then(|m| m.humidity),
        notes: metadata.and_then(|m| m.notes),
    };
    
    // Store event in chain
    let mut product_history = PRODUCT_HISTORY
        .load(deps.storage, &product_id)
        .unwrap_or_default();
    product_history.push(event.clone());
    PRODUCT_HISTORY.save(deps.storage, &product_id, &product_history)?;
    
    // Update product status
    update_product_status(deps.storage, &product_id, &event_type)?;
    
    Ok(Response::new()
        .add_attribute("action", "track_product")
        .add_attribute("product_id", product_id)
        .add_attribute("event_type", format!("{:?}", event_type))
        .add_attribute("handler", info.sender))
}

3. Trade Finance Contract

Automate letters of credit and trade finance operations:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct LetterOfCredit {
    pub id: String,
    pub importer: Addr,
    pub exporter: Addr,
    pub issuing_bank: Addr,
    pub advising_bank: Addr,
    pub amount: Coin,
    pub documents_required: Vec<RequiredDocument>,
    pub expiry_date: Timestamp,
    pub status: LCStatus,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub enum LCStatus {
    Issued,
    Confirmed,
    DocumentsSubmitted,
    DocumentsApproved,
    PaymentReleased,
    Completed,
    Expired,
}

pub fn submit_documents(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    lc_id: String,
    documents: Vec<Document>,
) -> Result<Response, ContractError> {
    let mut lc = LETTERS_OF_CREDIT.load(deps.storage, &lc_id)?;
    
    // Verify submitter is the exporter
    if info.sender != lc.exporter {
        return Err(ContractError::Unauthorized {});
    }
    
    // Verify LC is in correct status
    if lc.status != LCStatus::Confirmed {
        return Err(ContractError::InvalidStatus {});
    }
    
    // Validate all required documents are submitted
    validate_documents(&lc.documents_required, &documents)?;
    
    // Store documents
    SUBMITTED_DOCUMENTS.save(deps.storage, &lc_id, &documents)?;
    
    // Update LC status
    lc.status = LCStatus::DocumentsSubmitted;
    LETTERS_OF_CREDIT.save(deps.storage, &lc_id, &lc)?;
    
    Ok(Response::new()
        .add_attribute("action", "submit_documents")
        .add_attribute("lc_id", lc_id)
        .add_attribute("exporter", info.sender))
}

4. Inventory Management Contract

Real-time inventory tracking and automated reordering:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InventoryItem {
    pub sku: String,
    pub name: String,
    pub quantity: u64,
    pub reserved: u64,
    pub reorder_point: u64,
    pub reorder_quantity: u64,
    pub supplier: Addr,
    pub last_restocked: Timestamp,
}

pub fn update_inventory(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    updates: Vec<InventoryUpdate>,
) -> Result<Response, ContractError> {
    let mut messages = vec![];
    let mut attributes = vec![("action", "update_inventory")];
    
    for update in updates {
        let mut item = INVENTORY.load(deps.storage, &update.sku)?;
        
        match update.operation {
            Operation::Add => {
                item.quantity = item.quantity.saturating_add(update.quantity);
                item.last_restocked = env.block.time;
            }
            Operation::Remove => {
                if item.quantity < update.quantity {
                    return Err(ContractError::InsufficientInventory {
                        sku: update.sku,
                        available: item.quantity,
                        requested: update.quantity,
                    });
                }
                item.quantity = item.quantity.saturating_sub(update.quantity);
            }
            Operation::Reserve => {
                let available = item.quantity.saturating_sub(item.reserved);
                if available < update.quantity {
                    return Err(ContractError::InsufficientInventory {
                        sku: update.sku,
                        available,
                        requested: update.quantity,
                    });
                }
                item.reserved = item.reserved.saturating_add(update.quantity);
            }
        }
        
        // Check if reorder needed
        if item.quantity <= item.reorder_point && item.quantity > 0 {
            let reorder_msg = create_reorder_message(
                &item.supplier,
                &update.sku,
                item.reorder_quantity,
            )?;
            messages.push(reorder_msg);
            attributes.push(("reorder_triggered", &update.sku));
        }
        
        INVENTORY.save(deps.storage, &update.sku, &item)?;
    }
    
    Ok(Response::new()
        .add_messages(messages)
        .add_attributes(attributes))
}

Advanced Features

Cross-Contract Communication

Enable contracts to interact with each other:

// Call another contract
pub fn execute_cross_contract_order(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    order_details: OrderDetails,
) -> Result<Response, ContractError> {
    // Prepare order for order management contract
    let order_msg = WasmMsg::Execute {
        contract_addr: ORDER_CONTRACT.load(deps.storage)?.to_string(),
        msg: to_binary(&OrderExecuteMsg::CreateOrder {
            items: order_details.items,
            shipping: order_details.shipping,
        })?,
        funds: info.funds,
    };
    
    // Update inventory contract
    let inventory_msg = WasmMsg::Execute {
        contract_addr: INVENTORY_CONTRACT.load(deps.storage)?.to_string(),
        msg: to_binary(&InventoryExecuteMsg::ReserveItems {
            items: order_details.items.clone(),
        })?,
        funds: vec![],
    };
    
    Ok(Response::new()
        .add_message(order_msg)
        .add_message(inventory_msg)
        .add_attribute("action", "cross_contract_order"))
}

Event-Driven Architecture

Use events to trigger automated workflows:

// Emit custom events
pub fn emit_order_event(
    order_id: String,
    event_type: OrderEventType,
) -> Event {
    Event::new("order_event")
        .add_attribute("order_id", order_id)
        .add_attribute("event_type", format!("{:?}", event_type))
        .add_attribute("timestamp", Timestamp::now().to_string())
}

// Subscribe to events in another contract
pub fn handle_order_event(
    deps: DepsMut,
    env: Env,
    event: OrderEvent,
) -> Result<Response, ContractError> {
    match event.event_type {
        OrderEventType::PaymentConfirmed => {
            // Trigger fulfillment workflow
            start_fulfillment_process(deps, env, event.order_id)?
        }
        OrderEventType::Shipped => {
            // Update tracking system
            update_tracking_info(deps, env, event.order_id, event.tracking_info)?
        }
        OrderEventType::Delivered => {
            // Release payment to seller
            release_payment(deps, env, event.order_id)?
        }
    }
    
    Ok(Response::new())
}

Upgradeable Contracts

Implement upgrade patterns for contract evolution:

// Migration entry point
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(
    deps: DepsMut,
    _env: Env,
    msg: MigrateMsg,
) -> Result<Response, ContractError> {
    let ver = cw2::get_contract_version(deps.storage)?;
    
    // Ensure we are migrating from an allowed version
    if ver.contract != CONTRACT_NAME {
        return Err(ContractError::CannotMigrate {
            previous_contract: ver.contract,
        });
    }
    
    if ver.version > CONTRACT_VERSION {
        return Err(ContractError::CannotMigrateVersion {
            previous_version: ver.version,
            new_version: CONTRACT_VERSION.to_string(),
        });
    }
    
    // Perform migration logic
    match msg {
        MigrateMsg::UpdateConfig { new_config } => {
            CONFIG.save(deps.storage, &new_config)?;
        }
        MigrateMsg::AddFeature { feature } => {
            enable_new_feature(deps.storage, feature)?;
        }
    }
    
    // Update contract version
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
    
    Ok(Response::new()
        .add_attribute("action", "migrate")
        .add_attribute("version", CONTRACT_VERSION))
}

Testing Strategies

Unit Testing

#[cfg(test)]
mod tests {
    use super::*;
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
    use cosmwasm_std::{coins, from_binary};

    #[test]
    fn test_create_order() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info("buyer", &coins(1000, "ustate"));
        
        // Initialize contract
        let msg = InstantiateMsg { admin: None };
        let _res = instantiate(deps.as_mut(), env.clone(), info.clone(), msg).unwrap();
        
        // Create order
        let create_msg = ExecuteMsg::CreateOrder {
            items: vec![
                OrderItem {
                    sku: "PROD-001".to_string(),
                    quantity: 2,
                    price: Uint128::new(100),
                }
            ],
            shipping: ShippingInfo {
                address: "123 Main St".to_string(),
                method: ShippingMethod::Standard,
            },
        };
        
        let res = execute(deps.as_mut(), env, info, create_msg).unwrap();
        
        // Verify response
        assert_eq!(res.attributes.len(), 4);
        assert_eq!(res.attributes[0].key, "action");
        assert_eq!(res.attributes[0].value, "create_order");
    }
}

Integration Testing

use stateset_integration_tests::{Contract, ContractWrapper};

#[test]
fn test_order_fulfillment_flow() {
    let mut app = mock_app();
    
    // Deploy contracts
    let order_contract = deploy_order_contract(&mut app);
    let inventory_contract = deploy_inventory_contract(&mut app);
    let payment_contract = deploy_payment_contract(&mut app);
    
    // Test complete order flow
    let order_id = create_test_order(&mut app, &order_contract);
    confirm_payment(&mut app, &payment_contract, &order_id);
    verify_inventory_reserved(&mut app, &inventory_contract, &order_id);
    ship_order(&mut app, &order_contract, &order_id);
    confirm_delivery(&mut app, &order_contract, &order_id);
    verify_payment_released(&mut app, &payment_contract, &order_id);
}

Deployment & Management

Mainnet Deployment Checklist

  1. Security Audit: Complete third-party audit
  2. Gas Optimization: Profile and optimize gas usage
  3. Error Handling: Comprehensive error messages
  4. Admin Controls: Implement proper access control
  5. Upgrade Path: Plan for future updates

Monitoring & Analytics

# Query contract state
stateset query wasm contract-state smart CONTRACT_ADDR \
  '{"get_order":{"order_id":"ORD-12345"}}' \
  --chain-id stateset-mainnet

# Monitor contract events
stateset query txs --events 'wasm.contract_address=CONTRACT_ADDR' \
  --chain-id stateset-mainnet

# Check contract metrics
stateset query wasm contract-state smart CONTRACT_ADDR \
  '{"get_metrics":{}}' \
  --chain-id stateset-mainnet

Best Practices

1. Security First

  • Always validate inputs
  • Use proper access controls
  • Implement rate limiting
  • Handle all edge cases

2. Gas Efficiency

  • Minimize storage operations
  • Batch operations when possible
  • Use efficient data structures
  • Profile gas usage

3. Maintainability

  • Write comprehensive tests
  • Document all functions
  • Use clear naming conventions
  • Implement upgrade patterns

Next Steps