Practical examples of StxScript code and the Clarity output they generate.
Variables and Constants
Token Configuration
StxScript:
const TOKEN_NAME: string = "MyToken"; const TOKEN_SYMBOL: string = "MTK"; const MAX_SUPPLY: uint = 1000000u; let total_supply: uint = 0u; let contract_owner: principal = tx-sender;
Generated Clarity:
(define-constant TOKEN_NAME u"MyToken") (define-constant TOKEN_SYMBOL u"MTK") (define-constant MAX_SUPPLY u1000000) (define-data-var total_supply uint u0) (define-data-var contract_owner principal tx-sender)
Type Aliases
type Amount = uint; type Address = principal; type Balance = { amount: Amount, locked: bool }; let transfer_amount: Amount = 1000u;
Functions
Public and Read-Only Functions
StxScript:
@public function transfer(to: principal, amount: uint): Response<bool, uint> { if (amount == 0u) { return err(1u); } return ok(true); } @readonly function get_balance(account: principal): uint { return balances.get(account); } function validate_amount(amount: uint): bool { return amount > 0u && amount <= MAX_SUPPLY; }
Generated Clarity:
(define-public (transfer (to principal) (amount uint)) (if (is-eq amount u0) (err u1) (ok true))) (define-read-only (get-balance (account principal)) (map-get? balances account)) (define-private (validate-amount (amount uint)) (and (> amount u0) (<= amount MAX_SUPPLY)))
Generic Functions
function identity<T>(value: T): T { return value; } function first<T>(list: List<T>): Optional<T> { return list[0]; }
Control Flow
If/Else
@public function safe_transfer(amount: uint, to: principal): Response<bool, uint> { if (amount == 0u) { return err(1u); } let balance = get_balance(tx-sender); if (balance < amount) { return err(2u); } return ok(true); }
Match Expressions
@public function process_result(value: Optional<uint>): uint { match value { some(v) => v, none => 0u } } @public function handle_response(result: Response<uint, string>): uint { match result { ok(v) => v, err(e) => 0u } }
For Loops
@public function sum_range(limit: uint): uint { let sum: uint = 0u; for (let i = 0; i < limit; i = i + 1) { sum = sum + i; } return sum; }
Data Structures
Maps
map balances<principal, uint>; map allowances<{ owner: principal, spender: principal }, uint>; @public function get_allowance(owner: principal, spender: principal): uint { let key = { owner: owner, spender: spender }; match allowances.get(key) { some(amount) => amount, none => 0u } } @public function set_allowance(spender: principal, amount: uint): Response<bool, uint> { let key = { owner: tx-sender, spender: spender }; allowances.set(key, amount); return ok(true); }
Lists and Higher-Order Functions
@public function process_numbers(numbers: List<uint>): uint { let evens = filter(numbers, (x) => x % 2u == 0u); let doubled = map(evens, (x) => x * 2u); let total = fold(doubled, 0u, (acc, x) => acc + x); return total; }
Real-World Contracts
SIP-010 Fungible Token
const TOKEN_NAME: string = "Example Token"; const TOKEN_SYMBOL: string = "EXAM"; const TOKEN_DECIMALS: uint = 6u; const TOTAL_SUPPLY: uint = 1000000000000u; const ERR_UNAUTHORIZED: uint = 100u; const ERR_INSUFFICIENT_BALANCE: uint = 101u; let contract_owner: principal = tx-sender; map balances<principal, uint>; @public function transfer(amount: uint, sender: principal, recipient: principal, memo: Optional<buffer<34>>): Response<bool, uint> { if (sender != tx-sender) { return err(ERR_UNAUTHORIZED); } let sender_balance = get_balance(sender); if (sender_balance < amount) { return err(ERR_INSUFFICIENT_BALANCE); } balances.set(sender, sender_balance - amount); balances.set(recipient, get_balance(recipient) + amount); return ok(true); } @readonly function get_name(): Response<string, uint> { return ok(TOKEN_NAME); } @readonly function get_symbol(): Response<string, uint> { return ok(TOKEN_SYMBOL); } @readonly function get_decimals(): Response<uint, uint> { return ok(TOKEN_DECIMALS); } @readonly function get_balance(account: principal): uint { match balances.get(account) { some(balance) => balance, none => 0u } } @readonly function get_total_supply(): Response<uint, uint> { return ok(TOTAL_SUPPLY); }
Simple NFT Contract
const CONTRACT_NAME: string = "My NFT Collection"; const ERR_NOT_OWNER: uint = 1u; const ERR_NOT_FOUND: uint = 2u; let last_token_id: uint = 0u; map nft_owners<uint, principal>; map nft_metadata<uint, string>; @public function mint(metadata_uri: string): Response<uint, uint> { let token_id = last_token_id + 1u; last_token_id = token_id; nft_owners.set(token_id, tx-sender); nft_metadata.set(token_id, metadata_uri); return ok(token_id); } @public function transfer(token_id: uint, recipient: principal): Response<bool, uint> { match nft_owners.get(token_id) { some(owner) => { if (owner != tx-sender) { return err(ERR_NOT_OWNER); } nft_owners.set(token_id, recipient); return ok(true); }, none => err(ERR_NOT_FOUND) } } @readonly function get_owner(token_id: uint): Response<principal, uint> { match nft_owners.get(token_id) { some(owner) => ok(owner), none => err(ERR_NOT_FOUND) } }
Python API Usage
Basic Transpilation
from stxscript import StxScriptTranspiler transpiler = StxScriptTranspiler() result = transpiler.transpile('let balance: uint = 1000u;') print(result) # Output: (define-data-var balance uint u1000)
Batch Transpilation
from stxscript import StxScriptTranspiler from pathlib import Path def transpile_directory(src_dir: str, output_dir: str): transpiler = StxScriptTranspiler() src_path = Path(src_dir) out_path = Path(output_dir) out_path.mkdir(exist_ok=True) for stx_file in src_path.glob("*.stx"): with open(stx_file) as f: stx_code = f.read() try: clarity_code = transpiler.transpile(stx_code) output_file = out_path / f"{stx_file.stem}.clar" with open(output_file, "w") as f: f.write(clarity_code) print(f"Transpiled: {stx_file.name}") except Exception as e: print(f"Error in {stx_file.name}: {e}") transpile_directory("src/contracts", "build/contracts")
CLI Workflow
Development Workflow
# Create a new token project stxscript new my-token --template token cd my-token # Start development mode stxscript watch src/ --output build/ # In another terminal, run tests stxscript test # Format and lint stxscript fmt src/ stxscript lint src/ # Build for production stxscript build src/ build/
Package Management
# Initialize a new package stxscript pkg init --name my-project # Add dependencies stxscript pkg add token-lib --version "^1.0.0" stxscript pkg add utils --dev # Install all dependencies stxscript pkg install # List installed packages stxscript pkg list