Sway vs. Solidity Part 1: What’s The Difference?

Poolshark Protocol
6 min readOct 26, 2022

--

Fuel Network, The World’s Fastest Modular Execution Layer.

In being one of the first protocols to launch on Fuel Network, the Poolshark Protocol will be written in Sway, the native language designed specifically for the FuelVM.

It is heavily inspired by Rust makes and quite a few considerations regarding how to bring superior performance and flexibility to the web3 experience. It is UTXO-based instead of account-based like Solidity.

Many of those interested in Fuel Network will first want to know what makes Sway different and the concepts they need to get up to speed with in order to develop for the FuelVM.

If you missed our article on the core differences between the FuelVM and the EVM, we recommend visiting that first.

If you’d like to follow along with this article series and install the Fuel toolchain, you can visit the installation page in the Sway book.

Let’s dive right into it 🌊!

Sway Core Concepts

Before deep-diving here is a short list of the concepts we’re going to cover:

- Importing dependencies
- Contract storage
- Public functions
- Storage maps
- Require statements

Below is a sample NFT contract called main.sw that we will reference:

contract;use std::{
storage::StorageMap,
logging::log
};
struct MintEvent {
owner: Identity,
total_tokens: u64,
}
storage {
total_supply: u64 = 0,
max_supply: u64 = 0,
balances: StorageMap<Identity, u64> = StorageMap {},
}
abi NFT { #[storage(read)]
fn balance_of(owner: Identity) -> u64;
#[storage(read)]
fn max_supply() -> u64;
#[storage(read,write)]
fn mint(amount: u64, to: Identity);
}
impl NFT for Contract { #[storage(read)]
fn max_supply() -> u64 {
storage.max_supply
}
#[storage(read)]
fn balance_of(owner: Identity) -> u64 {
storage.balances.get(owner)
}
#[storage(read, write)]
fn mint(amount: u64, to: Identity) {
storage.balances.insert(to, storage.balances.get(to) + amount); storage.total_supply += amount; assert(storage.total_supply <= storage.max_supply); log(MintEvent {
owner: to,
total_tokens: amount,
});
}
}

The above is a basic implementation of an NFT contract, where users can call mint to increase their balance or call balance_of to check their balances.

If you would like to see a full version of an NFT implementation, you can jump to the sway applications Github repo.

We recommend reading through the rest of this article to ensure you understand the Sway basics first. Let’s go through the code line-by-line.

Declaring the Program Type

contract;

This line labels this file as the contract byte code type. The key features of a contract are that it is both callable and stateful.

We recommend checking the Program Types page if you would like to explore the other program typesProgram Types page.

Importing Dependencies

dep interface;

The dep keyword is used to import code from other libraries before the mention of the use keyword.

This will make all the other items, namely functions and structs, accessible from our contract.

Here will will implement the NFT ABI, which is a fancy way to refer to the set of functions that our contract will implement.

use std::{                         
chain::auth::msg_sender
storage::StorageMap };

use blocks declare what exact items will see usage from a given library, which could be structs, functions, or other public entities.

Within the std library, which you can find here, the msg_sender function is located with src/chain/auth.sw.

use blocks will always be of the pattern [lib_name_and_path]::[function_or_struct_name]. As seen here, the lib path portion can have multiple levels.

Sway book reference: Writing Libraries

Declaring Storage

“The English never abolish anything. They put it in cold storage.”

storage {
total_supply: u64,
max_supply: u64,
balances: StorageMap<Identity, u64> = StorageMap {},
}

In Solidity, global variables declared outside function braces are treated as contract storage. These values are used outside of contract calls to aggregate values to be used for future calls.

In Sway, you declare all the storage variables for your contract inside a storage block.

Since the FuelVM only supports up to u64, this is used as the standard size for all token supply values.

A u64 simply represents a 64-bit unsigned integer. If as a developer you’d like to use a signed value, I recommend taking a look at our I24 implementation being used in our AMM library.

Sway book reference: Contract Storage

The StorageMap Type

The StorageMap type is the equivalent of the mapping type used in Solidity. It is intended for storing key-value pairs which are typically used for ERC-20 balances.

In this example, the key would be the address of the user, with the value being the user’s token balance.

In Sway, we have the Identity type, which could be either a ContractId (i.e. another smart contract) or Address.

To interact with the StorageMap, we use both the get() and insert() methods to retrieve values or add/update values in the map.

Sway book reference: Storage Maps

Implementing a Contract ABI

impl NFT for Contract {

Here we are implementing the NFT ABI which we imported from the interface. This ABI will simply be defined as such:

library interface;abi NFT {
#[storage(read)]
fn total_supply() -> u64;
#[storage(read)]
fn max_supply() -> u64;
#[storage(read,write)]
fn mint() -> mint(amount: u64, to: Identity)
}

This will allow any connecting contracts or providers making external calls to interact with your contract.

Sway book reference: Writing a Smart Contract

Writing Methods

It’s not the Method. It’s the Mindset.

Methods in Sway that either read from or write to storage will require #[storage(read,write)] permissions depending on the level of access required for the method.

The max_supply Method

#[storage(read)]
fn max_supply() -> u64 {
storage.max_supply
}

Since max_supply is a u64 type we will set u64 as the return type (denoted by using -> u64 ).

The storage keyword allows us to access anything declared in the storage block.

The last line of our method will also be the return value, so there is no need for a return statement or a ; at the end of this line.

The total_supply Method

#[storage(read)]
fn balance_of(owner: Identity) -> u64 {
storage.balances.get(owner)
}

The StorageMap declared in our storage block has keys of type Identity, which can either resolve to a ContractId for a contract or Address for an address tied to a user key pair.

We call the get method on the balances StorageMap and pass the owner key to retrieve the balance for this Identity.

Again since this is our return value there is no need for a return statement nor a ; to complete our function body.

The mint Method

#[storage(read, write)]
fn mint(amount: u64, to: Identity) {
storage.balances.insert(to, storage.balances.get(to) + amount);
storage.total_supply += amount;
assert(storage.total_supply <= storage.max_supply);

log(MintEvent {
owner: to,
tokens_minted: amount,
});
}

Inside the mint method, we will modify storage variables and thus the permission of #[storage(read, write)] is required.

Next, we will assign an additional balance of the amount to the existing balance inside the storage.balances map.

The insert() method will insert or update values in our StorageMap. It takes the parameters key and value. The key will be used for future lookups to access the value inserted.

Next, we update total_supply by adding the amount we just minted to the user.

We then use assert(), which Solidity developers may recognize as similar to a require statement, to make sure we are not exceeding the max_supply in which case the transaction would revert.

Lastly, we use the log method to log the MintEvent similar to the emit keyword in Solidity, exposing the owner and how many NFTs they minted.

Sway book refence: Functions

Part 2: Compiling and Deploying

In the second part of this series, we will cover the process for compiling and deploying your contracts, taking you through the entire installation process as well as the contract deployment.

Hopefully you found this article insightful and now have some basic ideas about what Smart Contract Development looks like in Sway.

Feel free to join the Fuel Discord if you have any questions relating to developing in Sway and the Poolshark Discord if you have any questions relating to this article or the Decentralized Exchange we are building. See you in the next one!

Part 1 Complete ✅

Poolshark Protocol: Price-Time Priority for Ethereum.

--

--