How to migrate smart contracts from Ethereum’s Solidity to Soroban Rust
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 should consider migrating your smart contracts to Rust
Why would a blockchain developer choose Rust over Solidity?
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 smart, saving on 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 the 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 is Soroban?
Soroban is a smart contracts platform with sensibility, built-to-scale, batteries-included and developer-friendly wants.
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. The package for the module consists of - smart contracts environment, a Rust SDK, A CLI, and an RPC server. Writing and testing of the contracts can be carried out on developers' local machines or deployed to Testnet.
Which programming language is used for Stellar smart contracts?
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.
How to Build a Hello World Smart Contract
We will create two "Hello World" contracts: first in Solidity, then using the Soroban Rust SDK.
Here is the video if you want to follow along:
Solidity Version
Open the remix-ide in your browser by navigating to: https://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;
}
}
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){
This line defines a function named "hello."
- 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.
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 Rust SDK Version
Open the smart contract playground built for Soroban, okashi, in your browser by navigating to: https://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 { ... }: 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
{ 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 and 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.
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 here.
Stay tuned for more insights and tutorials in this series, and happy coding in the world of smart contracts!