After two decades navigating enterprise IT, I've learned that the best way to understand a new technology is to build something real with it. When I first approached Soroban—Stellar's smart contract platform—I decided to skip the theory-heavy tutorials and write actual code. This guide distills that hands-on experience into a practical path you can follow today.
Soroban runs on Rust, compiled to WebAssembly (Wasm), which gives us memory safety and predictable performance. Unlike gas-heavy EVM chains, Stellar's fees remain fractions of a cent, making it ideal for high-frequency tokenization use cases. Let me walk you through my first contract from zero to deployment.
Setting Up the Environment
Before writing a single line, you need a clean toolchain. I always recommend isolating your Web3 environments to avoid dependency conflicts—something I learned the hard way managing production systems.
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add the Wasm target
rustup target add wasm32-unknown-unknown
# Install the Stellar CLI
cargo install --locked stellar-cli
Verify everything works:
stellar --version
Then create your project and configure a testnet identity:
stellar contract init hello-soroban
cd hello-soroban
stellar keys generate --global andre --network testnet
stellar keys fund andre --network testnet
That last command funds your account with test XLM via Friendbot. When I, André Dias Moreira Prol, ran my first deployment, this funding step tripped me up—remember it, because an unfunded account silently fails.
Writing and Understanding the Contract
Here's a minimal but meaningful contract that stores and increments a counter—a pattern that underpins many real tokenization systems (think supply tracking or vote tallies).
#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Env, Symbol};
const COUNTER: Symbol = symbol_short!("COUNTER");
#[contract]
pub struct CounterContract;
#[contractimpl]
impl CounterContract {
pub fn increment(env: Env) -> u32 {
// Read current value, defaulting to zero
let mut count: u32 = env
.storage()
.instance()
.get(&COUNTER)
.unwrap_or(0);
count += 1;
// Persist the new value
env.storage().instance().set(&COUNTER, &count);
// Extend storage lifetime to avoid archival
env.storage().instance().extend_ttl(50, 100);
count
}
}
Three things worth highlighting from my experience:
-
#![no_std]removes the standard library, keeping the Wasm binary tiny—critical for on-chain cost efficiency. -
extend_ttlmanages state rent. Soroban charges for storage over time; forgetting this means your data gets archived. In one of my early forensic audits, I traced a "vanishing balance" bug directly to a missing TTL extension. -
instance()storage ties data to the contract lifecycle, ideal for global counters.
Compile it:
stellar contract build
Deploying and Invoking
Now the exciting part—putting your contract on the network. Deploy the compiled Wasm to testnet:
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/hello_soroban.wasm \
--source andre \
--network testnet
This returns a contract ID (starting with C...). Save it. Then invoke your function:
stellar contract invoke \
--id <YOUR_CONTRACT_ID> \
--source andre \
--network testnet \
-- increment
Each call returns the incremented value: 1, 2, 3. The entire deployment cost me under $0.01 in equivalent fees—a figure that still impresses clients when I compare it to the $5–$50 gas spikes common on legacy chains.
For production, I always add unit tests before deploying:
#[cfg(test)]
mod test {
use super::*;
use soroban_sdk::Env;
#[test]
fn test_increment() {
let env = Env::default();
let id = env.register(CounterContract, ());
let client = CounterContractClient::new(&env, &id);
assert_eq!(client.increment(), 1);
assert_eq!(client.increment(), 2);
}
}
Testing locally with a simulated Env is the single biggest time-saver I recommend—it catches logic errors long before they hit the chain, where every mistake becomes public and permanent.
Writing your first Soroban contract proves that enterprise-grade blockchain development is more accessible than the hype suggests, provided you respect fundamentals like storage rent and rigorous testing. Clone the starter repo, deploy your own counter today, and reach out to me, André Dias Moreira Prol, to share what you build.
Follow more articles by André Dias Moreira Prol on Medium.
Top comments (0)