#!/bin/bash # ============================================================================= # Synor Contract Template Generator # ============================================================================= # Creates a new smart contract project from template. # # Usage: # ./scripts/new-contract.sh [--description "Description"] # # Example: # ./scripts/new-contract.sh my-token --description "My custom token" # ============================================================================= set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" CONTRACTS_DIR="$PROJECT_DIR/contracts" # Colors GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } print_usage() { echo "Synor Contract Template Generator" echo "" echo "Usage: $0 [options]" echo "" echo "Options:" echo " --description, -d Contract description" echo " --help, -h Show this help" echo "" echo "Examples:" echo " $0 my-token" echo " $0 my-token --description \"Custom fungible token\"" } # Parse arguments CONTRACT_NAME="" DESCRIPTION="A Synor smart contract" while [[ $# -gt 0 ]]; do case $1 in --description|-d) DESCRIPTION="$2" shift 2 ;; --help|-h) print_usage exit 0 ;; -*) echo "Unknown option: $1" print_usage exit 1 ;; *) if [[ -z "$CONTRACT_NAME" ]]; then CONTRACT_NAME="$1" fi shift ;; esac done if [[ -z "$CONTRACT_NAME" ]]; then echo "Error: Contract name required" print_usage exit 1 fi # Validate contract name (lowercase, alphanumeric, hyphens) if ! [[ "$CONTRACT_NAME" =~ ^[a-z][a-z0-9-]*$ ]]; then echo "Error: Contract name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens" exit 1 fi # Convert to Rust package name (hyphens to underscores for module) RUST_NAME=$(echo "$CONTRACT_NAME" | tr '-' '_') PACKAGE_NAME="synor-$CONTRACT_NAME" CONTRACT_DIR="$CONTRACTS_DIR/$CONTRACT_NAME" # Check if already exists if [[ -d "$CONTRACT_DIR" ]]; then log_warn "Contract directory already exists: $CONTRACT_DIR" read -p "Overwrite? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1 fi rm -rf "$CONTRACT_DIR" fi log_info "Creating contract: $CONTRACT_NAME" # Create directory structure mkdir -p "$CONTRACT_DIR/src" # Create Cargo.toml cat > "$CONTRACT_DIR/Cargo.toml" << EOF [package] name = "$PACKAGE_NAME" version = "0.1.0" edition = "2021" description = "$DESCRIPTION" authors = ["Your Name "] license = "MIT" [lib] crate-type = ["cdylib"] [dependencies] synor-sdk = { path = "../../crates/synor-sdk", default-features = false } borsh = { version = "1.3", default-features = false, features = ["derive"] } [profile.release] opt-level = "z" # Optimize for size lto = true # Link-time optimization codegen-units = 1 # Single codegen unit for better optimization panic = "abort" # Abort on panic (smaller binaries) strip = true # Strip symbols EOF # Create lib.rs template cat > "$CONTRACT_DIR/src/lib.rs" << 'EOF' //! CONTRACT_DESCRIPTION //! //! # Methods //! - `init(...)` - Initialize the contract //! - Add more methods here... #![no_std] extern crate alloc; use alloc::vec::Vec; use borsh::BorshDeserialize; use synor_sdk::prelude::*; use synor_sdk::require; // ==================== Storage Keys ==================== mod keys { pub const OWNER: &[u8] = b"CONTRACT_NAME:owner"; pub const INITIALIZED: &[u8] = b"CONTRACT_NAME:initialized"; // Add more storage keys here... } // ==================== Data Structures ==================== // Add your custom structs here... // #[derive(BorshSerialize, BorshDeserialize)] // pub struct MyStruct { // pub field: u64, // } // ==================== Storage Helpers ==================== fn get_owner() -> Option
{ storage::get::
(keys::OWNER) } fn is_initialized() -> bool { storage::get::(keys::INITIALIZED).unwrap_or(false) } // ==================== Entry Points ==================== synor_sdk::entry_point!(init, call); /// Initialize the contract. fn init(params: &[u8]) -> Result<()> { require!(!is_initialized(), Error::invalid_args("Already initialized")); #[derive(BorshDeserialize)] struct InitParams { // Add your initialization parameters here // name: String, // value: u64, } let _params = InitParams::try_from_slice(params) .map_err(|_| Error::invalid_args("Invalid init params"))?; // Store owner storage::set(keys::OWNER, &caller()); storage::set(keys::INITIALIZED, &true); // Initialize your contract state here... Ok(()) } /// Handle contract calls. fn call(selector: &[u8], params: &[u8]) -> Result> { // Define method selectors let owner_sel = synor_sdk::method_selector("owner"); let example_sel = synor_sdk::method_selector("example_method"); match selector { s if s == owner_sel => { let owner = get_owner().unwrap_or(Address::zero()); Ok(borsh::to_vec(&owner).unwrap()) } s if s == example_sel => { #[derive(BorshDeserialize)] struct Args { value: u64, } let args = Args::try_from_slice(params) .map_err(|_| Error::invalid_args("Expected value"))?; // Implement your logic here let result = args.value * 2; Ok(borsh::to_vec(&result).unwrap()) } _ => Err(Error::InvalidMethod), } } // ==================== Internal Functions ==================== // Add your internal helper functions here... // ==================== Events ==================== // Define your events here... // #[derive(borsh::BorshSerialize)] // struct MyEvent { // field: u64, // } EOF # Replace placeholders sed -i '' "s/CONTRACT_DESCRIPTION/$DESCRIPTION/g" "$CONTRACT_DIR/src/lib.rs" 2>/dev/null || \ sed -i "s/CONTRACT_DESCRIPTION/$DESCRIPTION/g" "$CONTRACT_DIR/src/lib.rs" sed -i '' "s/CONTRACT_NAME/$RUST_NAME/g" "$CONTRACT_DIR/src/lib.rs" 2>/dev/null || \ sed -i "s/CONTRACT_NAME/$RUST_NAME/g" "$CONTRACT_DIR/src/lib.rs" log_success "Contract created: $CONTRACT_DIR" echo "" echo "Next steps:" echo " 1. Edit $CONTRACT_DIR/src/lib.rs to implement your contract" echo " 2. Build with:" echo " cargo build --manifest-path $CONTRACT_DIR/Cargo.toml --target wasm32-unknown-unknown --release" echo " 3. Deploy with:" echo " synor contract deploy target/wasm32-unknown-unknown/release/${PACKAGE_NAME//-/_}.wasm" echo ""