rs-soroban-sdk
Soroban SDK Skill
Soroban SDK is the Rust SDK for building smart contracts on the Stellar blockchain's Wasm-powered Soroban runtime.
Prerequisites
- Rust: v1.84.0 or higher
- Target: Install with
rustup target add wasm32v1-none - Stellar CLI: v25.1.0+ (recommended for building and testing)
- Install:
curl -fsSL https://github.com/stellar/stellar-cli/raw/main/install.sh | sh - Or:
brew install stellar-cli
- Install:
⚠️ Security First
Smart contracts handle valuable assets. Follow these rules to prevent vulnerabilities:
Do:
- ✅ Call
require_auth()before any state changes - ✅ Validate all inputs (amounts, addresses, array lengths)
- ✅ Use checked arithmetic (
.checked_add(),.checked_mul()) - ✅ Extend TTL on all persistent/instance storage writes
- ✅ Initialize contract only once with a guard flag
- ✅ Test authorization, overflow, and edge cases
Don't:
- ❌ Skip authorization checks
- ❌ Use unchecked arithmetic (can overflow/underflow)
- ❌ Allow reinitialization
- ❌ Forget to extend TTL on storage writes
- ❌ Trust external addresses without validation
See references/security.md for complete security guidance.
Core Contract Structure
Every Soroban contract follows this pattern:
#![no_std] // Required: excludes Rust std library (too large for contracts)
use soroban_sdk::{contract, contractimpl, Env};
#[contract]
pub struct MyContract;
#[contractimpl]
impl MyContract {
pub fn function_name(env: Env, param: Type) -> ReturnType {
// Implementation
}
}
Key requirements:
#![no_std]- Must be first line (standard library not available)- All contracts export as a single contract when compiled to WASM
- Function names max 32 characters
- Contract inputs must not be references
Key attributes:
#[contract]- Marks the struct as a contract type#[contractimpl]- Exports public functions as contract functions#[contracttype]- Converts custom types to/fromValfor storage#[contracterror]- Defines error enums withrepr(u32)#[contractevent]- Marks structs as publishable events
Environment (Env)
The Env type provides access to the contract execution environment. It's always the first parameter in contract functions.
pub fn my_function(env: Env) {
// Access storage
env.storage().persistent();
env.storage().temporary();
env.storage().instance();
// Get contract address
let contract_id = env.current_contract_address();
// Get ledger info
let ledger = env.ledger().sequence();
let timestamp = env.ledger().timestamp();
}
Storage Types
Soroban provides three storage types with different lifetimes and costs. See references/storage.md for detailed patterns.
Quick reference:
Persistent- Long-lived data (user balances, state)Temporary- Short-lived data (caching, temporary locks)Instance- Contract-wide configuration/metadata
Data Types
Core Types
Address- Universal identifier (contracts or accounts)Symbol- Short strings with limited charset (max 32 chars)Vec<T>- Growable array typeMap<K, V>- Ordered key-value dictionaryBytes- Growable byte arrayBytesN<N>- Fixed-size byte arrayString- UTF-8 string typeU256,I256- 256-bit integers
Type Macros
vec![&env, item1, item2]- Create Vecmap![&env, (key1, val1), (key2, val2)]- Create Mapsymbol_short!("text")- Create Symbol constantbytes!(&env, 0x010203)- Create Bytesbytesn!(&env, 0x010203)- Create BytesN
Authorization
⚠️ Critical: Authorization vulnerabilities are the #1 cause of smart contract exploits. Always call require_auth() before any state changes.
When a function requires authorization, use Address::require_auth():
pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
from.require_auth(); // ✅ ALWAYS FIRST
// Now authorized to proceed
}
Common mistake: Authorizing the wrong address
// ❌ WRONG: Authorizing recipient
pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
to.require_auth(); // Anyone can receive!
}
// ✅ CORRECT: Authorize sender
pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
from.require_auth(); // Sender must approve
}
For custom auth logic, see references/auth.md.
Testing
Use testutils feature for testing. Tests use Env::default() and register contracts:
#[test]
fn test() {
let env = Env::default();
let contract_id = env.register(MyContract, ());
let client = MyContractClient::new(&env, &contract_id);
let result = client.my_function(¶m);
assert_eq!(result, expected);
}
For advanced testing patterns, see references/testing.md.
Tokens
Work with tokens using the token module:
use soroban_sdk::token::{TokenClient, StellarAssetClient};
pub fn use_token(env: Env, token_address: Address, amount: i128) {
let token = TokenClient::new(&env, &token_address);
token.transfer(&from, &to, &amount);
}
See references/tokens.md for token integration patterns.
Events and Logging
Publish events for off-chain tracking:
env.events().publish((symbol_short!("transfer"), from, to), amount);
During development, use logging:
use soroban_sdk::log;
log!(&env, "Debug message: {}", value);
Error Handling
Define custom errors with #[contracterror]:
#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Error {
InvalidAmount = 1,
Unauthorized = 2,
InsufficientBalance = 3,
}
Use with panic_with_error! or assert_with_error!:
// Validate before operations
assert_with_error!(&env, amount > 0, Error::InvalidAmount);
assert_with_error!(&env, balance >= amount, Error::InsufficientBalance);
// Or panic directly
if amount == 0 {
panic_with_error!(&env, Error::InvalidAmount);
}
⚠️ Security: Always validate inputs to prevent:
- Integer overflow/underflow (use checked arithmetic)
- Invalid addresses or amounts
- Array length mismatches
- Division by zero
Deployment
Contracts can deploy other contracts:
use soroban_sdk::deploy::{Deployer, ContractIdPreimage};
let deployer = env.deployer();
let contract_id = deployer.deploy_wasm(&wasm_hash, &salt);
Common Patterns
State Management
Store contract state in Instance storage for contract-wide config:
const STATE_KEY: Symbol = symbol_short!("STATE");
pub fn init(env: Env, admin: Address) {
env.storage().instance().set(&STATE_KEY, &admin);
}
pub fn get_admin(env: Env) -> Address {
env.storage().instance().get(&STATE_KEY).unwrap()
}
Iterating Over Collections
Use iterator methods on Vec and Map:
let total: i128 = amounts
.iter()
.map(|x| x.unwrap())
.sum();
Cross-Contract Calls
Import contracts with contractimport! or create manual clients:
let other_contract = OtherContractClient::new(&env, &contract_address);
let result = other_contract.function(&args);
Project Setup
Requirements
- Rust toolchain v1.84.0 or higher (required for
wasm32v1-nonetarget) - Stellar CLI v25.1.0 or higher
- Install target:
rustup target add wasm32v1-none
Cargo.toml Configuration
Workspace-level Cargo.toml:
[workspace]
resolver = "2"
members = ["contracts/*"]
[workspace.dependencies]
soroban-sdk = "25"
[profile.release]
opt-level = "z"
overflow-checks = true
debug = 0
strip = "symbols"
debug-assertions = false
panic = "abort"
codegen-units = 1
lto = true
[profile.release-with-logs]
inherits = "release"
debug-assertions = true
Contract-level Cargo.toml:
[package]
name = "my-contract"
version = "0.0.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
doctest = false
[dependencies]
soroban-sdk = { workspace = true }
[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
Building Contracts
Recommended: Use Stellar CLI (automatically sets correct target and profile):
stellar contract build
Equivalent manual command:
cargo build --target wasm32v1-none --release
Output: target/wasm32v1-none/release/contract_name.wasm
Optimize for production:
stellar contract optimize --wasm target/wasm32v1-none/release/contract_name.wasm
Produces: contract_name.optimized.wasm
Additional Resources
For detailed information on specific topics, see:
- Storage patterns and TTL management
- Authorization and auth context
- Testing strategies and utilities
- Token integration and Stellar Asset Contracts
- Common contract patterns and examples
- Security best practices and vulnerabilities ⚠️ CRITICAL
Official documentation: https://developers.stellar.org/docs/build/smart-contracts
Security Quick Reference
Critical rules to prevent vulnerabilities:
- ✅ Always authorize first: Call
require_auth()before any state changes - ✅ Validate all inputs: Check amounts, addresses, array lengths
- ✅ Prevent overflow: Use checked arithmetic for all math operations
- ✅ Initialize once: Use initialization flag to prevent reinitialization
- ✅ Extend TTL: Always extend TTL on persistent/instance storage writes
- ✅ Choose storage wisely: Persistent for critical data, Temporary for cache
- ✅ Test thoroughly: Cover authorization, overflows, edge cases
See references/security.md for complete security guidance.
More from padparadscho/skills
rs-ratatui-crate
Build terminal user interfaces (TUIs) in Rust with Ratatui (v0.30). Use this skill whenever working with the ratatui crate for creating interactive terminal applications, including: (1) Setting up a new Ratatui project, (2) Creating or modifying terminal UI layouts, (3) Implementing widgets (lists, tables, charts, text, gauges, etc.), (4) Handling keyboard/mouse input and events, (5) Structuring TUI application architecture (TEA, component-based, or monolithic patterns), (6) Writing custom widgets, (7) Managing application state in a TUI context, (8) Terminal setup/teardown and panic handling, (9) Testing TUI rendering with TestBackend. Also triggers for questions about crossterm event handling in a Ratatui context, tui-input, tui-textarea, or any ratatui-* ecosystem crate.
22js-gnome-extensions
Build, debug, and maintain GNOME Shell extensions using GJS (GNOME JavaScript). Covers extension anatomy (metadata.json, extension.js, prefs.js, stylesheet.css), ESModule imports, GSettings preferences, popup menus, quick settings, panel indicators, dialogs, notifications, search providers, translations, and session modes. Use when the user wants to: (1) Create a new GNOME Shell extension, (2) Add UI elements like panel buttons, popup menus, quick settings toggles/sliders, or modal dialogs, (3) Implement extension preferences with GTK4/Adwaita, (4) Debug or test an extension, (5) Port an extension to a newer GNOME Shell version (45-49+), (6) Prepare an extension for submission to extensions.gnome.org, (7) Work with GNOME Shell internal APIs (Clutter, St, Meta, Shell, Main).
7js-gnome-apps
Build native GNOME desktop applications using JavaScript (GJS) with GTK 4, Libadwaita, and the GNOME platform. Use when the user wants to create, modify, or debug a GNOME app written in JavaScript/GJS, including UI design with XML or Blueprint, GObject subclassing, Meson build setup, Flatpak packaging, or any task involving GJS bindings for GLib/GIO/GTK4/Adw libraries. Also use when working with `.ui` files, `meson.build`, GResource XML, GSettings schemas, `.desktop` files, or Flatpak manifests in a GJS project context.
6js-stellar-sdk
Guide for building applications with the Stellar JS SDK (@stellar/stellar-sdk). Use when working with the Stellar blockchain in JavaScript/TypeScript — including sending payments, creating accounts, issuing assets, managing trustlines, trading on the DEX, querying Horizon, interacting with Stellar RPC, streaming events, building and signing transactions, multisig, claimable balances, sponsored reserves, SEP-10 auth, federation, fee-bump transactions, and interacting with Soroban smart contracts via the JS SDK. Covers all @stellar/stellar-sdk usage patterns (Horizon module, rpc module, contract module, TransactionBuilder, Keypair, Operation, Asset, etc.).
5js-stronghold-sdk
Guide for integrating and building with the Stronghold Pay JS SDK and REST API for payment processing. Use when working with Stronghold Pay payment integration, accepting ACH/bank debit payments, linking bank accounts, creating charges/tips, generating PayLinks, or building checkout flows — in sandbox or live environments. Covers Stronghold.Pay.JS drop-in UI, REST API v2 endpoints, PayLink hosted payment pages, customer token management, and payment source handling.
3rs-yew-crate
Expert guidance for building Rust + WebAssembly frontend web applications using the Yew framework (v0.22). Use when creating, modifying, debugging, or architecting Yew applications — including function components, hooks, props, routing, contexts, events, server-side rendering, agents, and Suspense. Covers project setup with Trunk, the html! macro, state management, data fetching, and integration with the broader Yew/WASM ecosystem (yew-router, gloo, wasm-bindgen, web-sys, stylist, yewdux).
2