James Bachini

5 Tips For Migrating Solidity Code To Rust Soroban

Solidity To Soroban

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"), &timestamp);
        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.


Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.


Posted

in

, , , ,

by

Tags: