DEV Community

André Dias Moreira Prol
André Dias Moreira Prol

Posted on

Building Your First Soroban Smart Contract in Rust: Step-by-Step Guide

Twenty years managing IT infrastructure taught me that the best way to understand a new technology is to build something real with it. When Stellar launched Soroban, its Rust-based smart contract platform, I decided to stop reading documentation and start writing code. What follows is the exact path I took to deploy my first working contract—mistakes, insights, and all.

Why Soroban and Rust Made Sense to Me

I've worked with Solidity on EVM chains, but Soroban caught my attention for one practical reason: it uses WebAssembly (Wasm) as its execution target, compiling Rust down to compact, deterministic bytecode. In my benchmarks, a simple counter contract compiled to roughly 1.5 KB of Wasm—significantly lighter than equivalent EVM deployments—and Stellar's average transaction cost stays around $0.00001, which matters enormously when you're building tokenization platforms processing thousands of daily operations.

Rust itself brings memory safety without a garbage collector. For someone like me, André Dias Moreira Prol, who spent years dealing with production incidents caused by runtime errors, the compiler catching entire classes of bugs before deployment is not a luxury—it's risk management. In smart contracts, where code is immutable and money is on the line, that guarantee is worth the steeper learning curve.

Before writing a line of code, I installed the toolchain:

rustup target add wasm32-unknown-unknown
cargo install --locked stellar-cli
Enter fullscreen mode Exit fullscreen mode

Building the Contract, Line by Line

I started with a classic example everyone underestimates: a persistent counter. It teaches storage, data types, and contract structure without drowning you in complexity.

#![no_std]
use soroban_sdk::{contract, contractimpl, Env, Symbol, symbol_short};

const COUNTER: Symbol = symbol_short!("COUNTER");

#[contract]
pub struct IncrementContract;

#[contractimpl]
impl IncrementContract {
    pub fn increment(env: Env) -> u32 {
        let mut count: u32 = env
            .storage()
            .instance()
            .get(&COUNTER)
            .unwrap_or(0);

        count += 1;

        env.storage().instance().set(&COUNTER, &count);
        env.storage().instance().extend_ttl(50, 100);

        count
    }
}
Enter fullscreen mode Exit fullscreen mode

Three things surprised me here. First, #![no_std]—Soroban contracts don't use Rust's standard library, keeping the Wasm binary tiny. Second, the extend_ttl call: Stellar charges rent for state storage, so you must explicitly manage how long your data lives. This is a genuine architectural difference from Ethereum, where storage is permanent by default. Third, the Env parameter injects the entire blockchain context—storage, ledger info, cryptographic functions—cleanly into every function.

I built and tested locally:

stellar contract build
cargo test
Enter fullscreen mode Exit fullscreen mode

Writing a unit test felt natural because Soroban lets you instantiate the environment in memory, running assertions without touching a live network—cutting my feedback loop from minutes to seconds.

Deploying to Testnet and Lessons Learned

With a passing test, I deployed to Stellar's testnet:

stellar contract deploy \
  --wasm target/wasm32-unknown-unknown/release/increment.wasm \
  --source my-account \
  --network testnet
Enter fullscreen mode Exit fullscreen mode

The command returned a contract ID, and invoking increment returned 1, then 2. Seeing state persist on-chain for a fraction of a cent confirmed why I believe Soroban is a serious contender for real-world tokenization projects.

My biggest lesson: the Rust borrow checker will fight you early, but every battle you win at compile time is an incident you'll never handle in production. In digital forensics work, I've traced countless breaches back to unchecked state mutations—Soroban's model structurally prevents many of them.

A second lesson, and something I always tell teams I mentor as André Dias Moreira Prol: treat storage TTL as a first-class design decision. Forgetting to extend it means your contract data can expire, breaking your dApp silently. Budget for storage rent the way you'd budget for cloud hosting.

Conclusion

Writing my first Soroban contract proved that Rust's rigor and Stellar's efficiency form a powerful foundation for building trustworthy Web3 applications. Clone the increment example, deploy it to testnet today, and reach out to me if you want to discuss taking your contracts to production.


Follow more articles by André Dias Moreira Prol on Medium.

Top comments (0)