Loading...
Loading...
Expert guidance for building smart contracts on Stellar using the Soroban Rust SDK. Use this skill when working with Soroban smart contracts for tasks including (1) creating new contracts with [contract] and [contractimpl] attributes, (2) implementing storage with Persistent, Temporary, or Instance storage types, (3) working with auth contexts and authorization, (4) handling tokens and Stellar Asset Contracts, (5) writing tests with testutils, (6) deploying contracts, (7) working with events and logging, (8) using crypto functions, (9) debugging contract errors, (10) security best practices and vulnerability prevention, (11) avoiding common security pitfalls like missing authorization, integer overflow, or reinitialization attacks.
npx skill4agent add padparadscho/skills rs-soroban-sdkrustup target add wasm32v1-nonecurl -fsSL https://github.com/stellar/stellar-cli/raw/main/install.sh | shbrew install stellar-clirequire_auth().checked_add().checked_mul()#![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
}
}#![no_std]#[contract]#[contractimpl]#[contracttype]Val#[contracterror]repr(u32)#[contractevent]Envpub 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();
}PersistentTemporaryInstanceAddressSymbolVec<T>Map<K, V>BytesBytesN<N>StringU256I256vec![&env, item1, item2]map![&env, (key1, val1), (key2, val2)]symbol_short!("text")bytes!(&env, 0x010203)bytesn!(&env, 0x010203)require_auth()Address::require_auth()pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
from.require_auth(); // ✅ ALWAYS FIRST
// Now authorized to proceed
}// ❌ 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
}testutilsEnv::default()#[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);
}tokenuse 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);
}env.events().publish((symbol_short!("transfer"), from, to), amount);use soroban_sdk::log;
log!(&env, "Debug message: {}", value);#[contracterror]#[contracterror]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Error {
InvalidAmount = 1,
Unauthorized = 2,
InsufficientBalance = 3,
}panic_with_error!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);
}use soroban_sdk::deploy::{Deployer, ContractIdPreimage};
let deployer = env.deployer();
let contract_id = deployer.deploy_wasm(&wasm_hash, &salt);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()
}let total: i128 = amounts
.iter()
.map(|x| x.unwrap())
.sum();contractimport!let other_contract = OtherContractClient::new(&env, &contract_address);
let result = other_contract.function(&args);wasm32v1-nonerustup target add wasm32v1-none[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[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"] }stellar contract buildcargo build --target wasm32v1-none --releasetarget/wasm32v1-none/release/contract_name.wasmstellar contract optimize --wasm target/wasm32v1-none/release/contract_name.wasmcontract_name.optimized.wasmrequire_auth()