synor/scripts/new-contract.sh
Gulshan Yadav 48949ebb3f Initial commit: Synor blockchain monorepo
A complete blockchain implementation featuring:
- synord: Full node with GHOSTDAG consensus
- explorer-web: Modern React blockchain explorer with 3D DAG visualization
- CLI wallet and tools
- Smart contract SDK and example contracts (DEX, NFT, token)
- WASM crypto library for browser/mobile
2026-01-08 05:22:17 +05:30

267 lines
6.9 KiB
Bash
Executable file

#!/bin/bash
# =============================================================================
# Synor Contract Template Generator
# =============================================================================
# Creates a new smart contract project from template.
#
# Usage:
# ./scripts/new-contract.sh <contract-name> [--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 <contract-name> [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 <your@email.com>"]
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<Address> {
storage::get::<Address>(keys::OWNER)
}
fn is_initialized() -> bool {
storage::get::<bool>(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<Vec<u8>> {
// 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 ""