How to migrate smart contracts from Ethereum’s Solidity to Soroban Rust

Author

Julian Martinez

Publishing date

Developers

Smart Contracts

Rust v. Solidity

Why would a blockchain developer choose Rust over Solidity?

In this tutorial, we'll explore the intricacies of two major smart contract programming environments: Ethereum's Solidity and Soroban’s Rust SDK and why you should consider migrating your smart contracts to Rust.

In the blockchain and smart contract realm, Rust is a standout choice for developers, and here's why:

  • Speed & Efficiency: Rust whizzes through tasks like a sports car in style. It is super fast, even outpacing C++ when it comes to speed and efficiency so that your blockchain operations are not just quick but also saves on computing resources.
  • Type Safety: Picture Rust's type system as a meticulous inspector, who is watching each bit of your code at compile time. This means fewer errors and a safer environment for your smart contracts.
  • Memory Safety Without the Overhead: Rust boasts top-shelf memory safety, acting as an invisible shield against vulnerabilities critical in the blockchain world. And it does this leanly without needing a garbage collector, keeping your projects lean and fortified.
  • Conquering Concurrency with Ease: In blockchain, handling simultaneous transactions is like juggling fireballs. Rust excels in managing multiple operations seamlessly, preventing the common complications seen in other languages. This leads to faster, safer processing of transactions, enhancing the overall performance of your smart contracts.

Rust combines speed, safety, and execution efficiency making it an ideal language for blockchain development where such qualities are demanded. So how does Rust stack up against Solidity?


What's the difference between EVM and Soroban?

What is EVM?

The Ethereum Virtual Machine (EVM) is a core component of the Ethereum blockchain network. It is a virtual environment that allows for the execution of smart contracts and decentralized applications (dApps). While Ethereum is the primary network utilizing the EVM, other blockchain platforms have adopted or created compatible versions of the EVM. For instance:

  • Avalanche has its own virtual machine, the Avalanche Virtual Machine (AVM), but it also supports the EVM through its C-Chain, enabling compatibility with Ethereum-based applications.
  • Optimism and Polygon are Layer 2 solutions built on top of the Ethereum blockchain. They use Optimistic Rollups and Polygon's own technology, respectively, but are compatible with the EVM. This means they can run Ethereum smart contracts and dApps.

Each blockchain network can have its own consensus mechanisms, underlying architecture, and protocol implementations. Geth (Go Ethereum, an implementation of an Ethereum node in the Go programming language) is specifically an Ethereum client, and while other networks might draw inspiration or use aspects of Ethereum's technology, they often have distinct core protocols and implementations.

In EVM Land, Solidity is the go-to language for developing smart contracts. Here's a quick rundown for my fellow builders:

  • Object-Oriented Approach: Just like other OOP languages, Solidity organizes code around data and objects, not just functions and logic.
  • High-Level Language: It abstracts away from the nitty-gritty of computer hardware, making development smoother and more intuitive.
  • Statically-Typed: Solidity checks your code for errors and type mismatches at compile time, saving you from a lot of headaches later.

What makes Solidity stand out is its role in powering decentralized transactions and managing blockchain accounts. Plus, if you're comfortable with JavaScript, C++, and Python you'll find Solidity's syntax familiar.

What's the difference between EVM and Soroban?

What is Soroban?

Soroban is a smart contracts platform designed to be sensible, built-to-scale, batteries-included, and developer-friendly.

While it works great with Stellar being that it shares the blockchain's values of scale and sensibility, it neither depends nor requires Stellar at all and can be used by any transaction processor, including other blockchains, L2s, and permissioned ledgers.

Currently, Soroban is available as a part of the v20 of Stellar protocol stable release on Testnet. The package for the module consists of - smart contracts environment, a Rust SDK, A CLI, an RPC server, and additional modules tailored for smart contracts on Stellar. Users have the option to write and test contracts on their local machines or deploy them to Testnet for a more realistic simulation.

Introduced in 2022, the Soroban Rust SDK is a suite of tools specifically for writing smart contracts on the Soroban platform. Built on Rust, it enables developers to create decentralized finance applications, automated market makers, and tokenized assets, while also leveraging some of Stellar's core functionalities.

Hello World

How to Build a Hello World Smart Contract

We will create two "Hello World" contracts: first in Solidity, then using the Soroban Rust SDK.

Solidity

Solidity Version

Open the remix-ide in your browser by navigating to: remix.ethereum.org/

Click on the “create new file” icon in the "File Explorer" tab.

Type the file name “HelloWorld.sol” and enter the following code into the ide:

```

// SPDX-License-Identifier: MIT

// compiler version must be greater than or equal to 0.8.20 and less than 0.9.0

pragma solidity >=0.7.0 <0.9.0;




contract HelloWorld {

function hello(string memory to) public pure returns(string memory){

string memory greeting = string(abi.encodePacked("hello ", to));

return greeting;

}

}

```

Review

Let's take a quick intermission to break down the code

```
// SPDX-License-Identifier: MIT
```

This comment indicates the license under which the code is released (MIT License).

```
pragma solidity >=0.7.0 <0.9.0;
```

This line specifies that this code is compatible with Solidity compiler versions greater than or equal to 0.7.0 and less than 0.9.0. It sets compiler version boundaries to ensure code compatibility and expected behavior.


```
contract HelloWorld {
```

Here, we declare a Solidity contract named "HelloWorld."

```
function hello(string memory to) public pure returns(string memory){
```
  • It takes one argument, a string named "to," which represents the name of the person you want to greet.
  • The function is marked as "public," which means it can be called externally.
  • The "pure" keyword indicates that this function does not modify the contract's state.

```
string memory greeting = string(abi.encodePacked("hello ", to));
```

Inside the "hello" function, a new string variable "greeting" is declared.

  • It is constructed by concatenating "hello" with the provided name using the **abi.encodePacked** function.
  • The result is stored in the "greeting" variable.
```
return greeting;
```

Finally, the function returns the "greeting" string as the result of the function call.

Solidity

Now back to our regularly scheduled programming(🥁)

Once the code is in Remix, click the "Solidity Compiler" icon below the “File Explorer” icon.

Then, click “Compile HelloWorld.sol” or simply press `cmd+s`

Once compiled successfully click the icon below “Solidity Compiler” that is “Deploy & Run Transactions”.

Without changing any of the values as shown above just click the “Deploy” button to deploy your smart contract. Once deployed you will find your smart contract just below in “Deployed Contracts” heading.

Click “>” before your contract you will see a button “hello” below as our contract has a hello function variable that returns a string composed of “hello” + the value you passed in for the `to` argument.

Define an value for to and then click the “hello” button to return the greeting.

Nicely done! Now for the real Mccoy!

Soroban

Soroban Rust SDK Version

Open the smart contract playground built for Soroban, okashi, in your browser by navigating to: okashi.dev/

Start a new project and name it HelloWorld.

Enter the following code into the IDE:

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

#[contract]
pub struct Contract;

#[contractimpl]
impl Contract {
    /// Say Hello to someone or something.
    /// Returns a length-2 vector/array containing 'Hello' and then the value passed as `to`.
    pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
        vec![&env, symbol_short!("Hello"), to]
    }
}
```

Time for another commercial break already!?!

Don't worry this one is going to help you polish up on your Rust(🥁)

```
#![no_std]
```

This directive is used at the beginning of the Rust code to specify that the standard library (std) should not be included in the build. In Soroban contracts, the standard library is excluded because it's large and not suitable for deployment on blockchains.

```
use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec};
```
  • The **use** keyword is used to import external dependencies or modules into the current Rust code.
  • **soroban_sdk**: This is the crate/module that provides the necessary functionalities and types for Soroban contracts.
  • **{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec}**: These are the specific items being imported from the **soroban_sdk** module, including attributes, macros **(contract, contractimpl, symbol_short!)**, and data types **(Env, Symbol, Vec)**.

```
#[contract]
pub struct Contract;
```
  • **#[contract]** is an attribute applied to the Contract struct, designating it as the type to which contract functions are associated. It implies that this struct will have contract functions implemented for it.
  • **pub struct Contract;** defines a public struct named Contract. In Soroban contracts, contract functions are associated with this struct.
```
#[contractimpl]
impl Contract {
    pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
        vec![&env, symbol_short!("Hello"), to]
    }
}
```
  • **#[contractimpl]** is an attribute that is applied to the **impl** block for the **Contract** struct, indicating that this block contains the implementation of contract functions.
  • **impl Contract { ... }**: This is the implementation block for the Contract struct, where contract functions are defined.
  • **pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> { ... }**: This line defines a public function named **hello**. It takes two arguments, **env** of type **Env** and "to" of type **Symbol**(in this case, a string of up to 8 characters). It also specifies the return type as **Vec<Symbol>**
  • **{ vec![&env, symbol_short!("Hello"), to] }**: This block of code is where a length-2 vector/array containing "Hello" and then the value passed as "to" is constructed and returned.

That's all the breaks we have for today. Don't get crabby on me!(🥁)

Now that the code is in the editor, compile it by clicking the compile button or pushing "cmd+k"

Open the contract tab and push the `hello()` button

Pass in an value for `to` and click the “call” button

The "Console" tab should open and you should see your message!

Comparison

Conclusion

Both Solidity and Soroban provide the functionality to declare public functions. However, their approaches to data handling and state management differ, influenced by their core languages – JavaScript for Solidity and Rust for Soroban. Solidity is ideal for those familiar with JavaScript, while Soroban's Rust foundation offers advantages in concurrency and safety.

Learn More

Additional Resources

For developers interested in transitioning from EVM to Soroban, we have comprehensive documentation that covers everything from the basics of the Soroban Rust SDK compared to Solidity, up to deploying your own smart contracts with Rust. Learn more about migrating from EVM here.

If you’re looking for more tools and want to learn more about the sdk, you can check out the official Soroban docs.

Stay tuned for more insights and tutorials in this series, and happy coding in the world of smart contracts!