Here are five tips for developers migrating from Solidity to Soroban.
1. Embrace .env
In Solidity, global variables like msg.sender, msg.value, and msg.data provide transaction context. Soroban replaces these with the Env object, a powerful interface to the contract’s execution environment. Env gives you access to contract data, ledger details, authentication, and more, making it a central hub for contract interactions.
#![no_std]
use soroban_sdk::{contract, contractimpl, Env, Symbol};
#[contract]
pub struct EnvStorage;
#[contractimpl]
impl EnvStorage {
pub fn store_env_data(env: Env) {
let timestamp = env.ledger().timestamp();
let sequence = env.ledger().sequence();
env.storage().set(Symbol::short("timestamp"), ×tamp);
env.storage().set(Symbol::short("sequence"), &sequence);
}
}
2. Require Auth
Solidity often relies on custom logic and modifiers (e.g., onlyOwner) for authorization. Soroban simplifies this with built-in methods like require_auth and require_auth_for_args on the Address object, enforced by the Soroban host during execution. This reduces boilerplate and enhances security by handling signatures and replay prevention at the protocol level.
The invoker address needs to be passed through to public functions in Soroban and then checked to using require_auth like this
impl Contract {
pub fn transfer(env: Env, my_address: Address, amount: i128) {
my_address.require_auth();
// Function logic to transfer
}
}
3. Stacking Crates
Solidity’s inheritance model (using is) allows contracts to inherit functions and state. Rust, however, does not support traditional inheritance. Instead, Soroban leverages composability through crates and the contractimport! macro, enabling modular reuse of code across contracts.
// event.rs
pub fn mint(e: &Env, admin: Address, to: Address, amount: i128) {
let topics = (symbol_short!("mint"), admin, to);
e.events().publish(topics, amount);
}
// contract.rs
use crate::event::mint;
#[contract]
pub struct Token;
#[contractimpl]
impl Token {
pub fn mint(e: Env, to: Address, amount: i128) {
let admin = e.current_contract_address();
mint(&e, admin, to, amount);
}
}
Use use to import functions from other modules or crates, and contractimport! to interact with deployed contracts via generated clients. This composability fosters reusable, modular code without the “is-a” relationship of Solidity.
4. Do Panic!
Solidity uses require and revert to handle errors, often with custom error messages. In Soroban, Rust’s Result type and panic! macro provide robust error handling. Result ensures predictable error states, while panic! is akin to Solidity’s revert for critical failures.
pub fn simple_deposit(amount: u32) {
if amount < 1_000_000 {
panic!("amount too low");
}
}
5. Function Visibility
Solidity’s visibility specifiers (public, external, internal, private) control function access. Soroban uses Rust’s visibility system, offering finer granularity with pub, pub(crate), pub(super), and implicit private.
mod outer {
pub fn get_public_field() -> u32 { 1 }
pub(crate) fn get_crate_field() -> u32 { 2 }
}
#[contract]
pub struct NewContract;
#[contractimpl]
impl NewContract {
pub fn get_public_fields() -> u32 {
outer::get_public_field()
}
}
Use pub for external access, pub(crate) for crate-internal access, and leave functions private by default (no pub). This aligns with Rust’s privacy first philosophy, differing from Solidity’s explicit visibility keywords.
Soroban’s design prioritizes security, flexibility, and testability
- Built-in Authorization – Reduces vulnerabilities by handling authentication at the host level.
- Composability – Enables modular, reusable code via crates and contractimport!.
- Rust’s Safety – Prevents common errors like overflows with Result and checked_ functions.
- Stellar Integration – Leverages Stellar’s fast, low-cost transactions and native token support.
Transitioning from Solidity to Soroban requires adapting to Rust’s safety first philosophy and Soroban’s unique features like Env and built-in authorization.
By understanding these key differences and Rust’s robust tooling you’ll be well equipped to build secure, efficient smart contracts on Stellar.