Soroban Quest - Hello World
Tags: soroban, stellar, tutorial
Published: 2022-11-24 19:13:05

On the [last post](https://dev.to/altug/soroban-quest-getting-familiar-with-the-workspace-17h9), we booted up our GitPod environment and now are ready to tackle the first Soroban Quest: Hello World!

## Understanding `README.md`

Let's begin questing by opening the `quests` folder in our Explorer. We can see multiple quests existing here. Since we will tackle the first quest right now, let's open the `1-hello-world` folder by clicking on it. Then, select `README.md` for more information about what to do on this quest.

![Hello World README](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5jc6g2kugn0g2n0f6qw7.png)

We can see that we have to use our Stellar Quest account to deploy and invoke the 1 Hello World contract on the Stellar Futurenet. What does any of these words mean? Let's check them out.

## Setting Up Our Stellar Quest Account

If we missed it, or are using another workspace, we should use `sq login` to login to our Stellar Quest account. This way, our progress can be saved to our account, and we can get sweet NFTs to our connected wallet. If the `1-hello-world` folder is missing, we can use `sq pull` to get the newest copy of the repository from GitHub.

> #### Pull? From where?
>
> `sq pull` uses `git` underneath to "pull" the newest changes from the [soroban quest repository](https://github.com/tyvdh/soroban-quest) to our local workspace. [git](https://git-scm.com/) is a version control program with excellent remote and local repository synchronization support, so that's what is happening here. `sq pull` accomplishes it in three steps:
>
> 1. Uses `git stash` to save our changes into a stash, so that collisions between the remote repository and our repository do not occur.
> 2. Uses `git pull` to pull the changes from the [soroban quest repository](https://github.com/tyvdh/soroban-quest).
> 3. Uses `git stash pop` to reapply the saved changes to our workspace.
>
> It is pretty useful for saving our work on the workspace, while having the ability to add new stuff!

After setting up our account and everything, we can use `sq play 1` to start questing! We should accept the funding by the prompt, as we will need some Futurenet Lumens for transacting. If you accidentally pressed no, you can use `sq fund [account]`, with account being the public key given to you for the quest. Don't forget to remove the brackets!

## Examining the Contract

On the `src` folder, we can see two files: `lib.rs` and `test.rs`. `lib.rs` contains the source code of the Soroban contract given on this quest. Let's begin checking out the code.

```rust
// We don't include the standard library to minimize compiled
// size. We also import a few macros and types we need from the
// `soroban_sdk`.
#![no_std]
use soroban_sdk::{contractimpl, symbol, vec, Env, Symbol, Vec};

pub struct HelloContract;

// Our `HelloContract` implementation contains only one function,
// `hello()`. This function will receive a `to` argument, and
// return a Vec made up of "Hello" and the supplied `to` value.
#[contractimpl]
impl HelloContract {
    pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
        vec![&env, symbol!("Hello"), to]
    }
}

// This `mod` declaration inserts the contents of `test.rs` into
// this file.
mod test;
```

The Soroban contracts are written in [Rust](https://www.rust-lang.org/), which is the hottest programming language at the moment. If you are not familiar with Rust, no worries! The contracts are extremely well commented, and it is quite understandable if you are experienced with another programming language. Let's dive deeper into the contract's code.

> #### What is Rust and Why is it Everywhere?
>
> [Rust](https://www.rust-lang.org/) is a systems programming language, which is known by it's memory safety. In addition to being memory safe, it is also *blazingly fast*, which makes it a popular programming language amongst programmers. The memory safety aspect is important, since [70% of the CVEs are caused by memory safety issues](https://msrc-blog.microsoft.com/2019/07/16/a-proactive-approach-to-more-secure-code/). So, to write a fast and secure code, a different approach than C and C++, must be employed. That's why Rust is everywhere!

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

pub struct HelloContract;
```
The `#![no_std]` line tells the Rust compiler to not include the standard library, as it is quite large and is not fully supported by the Soroban environment. The useful components are already implemented in the `soroban_sdk`, so we don't need to include the standard library! The second line tells the compiler to use the implementations of `contractimpl`, `symbol`, `vec`, `Env`, `Symbol`, and `Vec` from the `soroban_sdk` library. We will use these lines almost every time when we are developing a Soroban contract. The next line tells the Soroban Runtime that our contract's name is `HelloContract`. After these definitions, we can check the implementation of the contract.

```rust
#[contractimpl]
impl HelloContract {
    pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
        vec![&env, symbol!("Hello"), to]
    }
}
```

The implementations of Soroban contracts are marked with `#[contractimpl]` to tell the compiler to do the right thing. In our contract implementation of the `HelloContract`, we can see that we have a *public* function, denoted with `pub fn`. Public functions are functions on a contract which are invokable by everyone using the Soroban network. The `hello` function has two arguments, and returns a `Vector` of `Symbol`s. A `Symbol` is a string-like value, which consists of at most 10 characters. A `Vector` can be defined as an array with the capacity to grow indefinitely.

The first input argument is `env` of type `Env`. This parameter can be found on every functiion that deals with the state of the Soroban network. It is generally used in each function, as it supplies some additional functionality. The `env` argument is not supplied by the invoker of the function, and is added automatically on function invocation. 

The second input argument is `to` of type `Symbol`. Symbols can be assumed as strings of a maximum length of 10. They provide cost and space efficiency, and are widely used for small data.

The function returns a `Vector`, using the macro `vec!`. It returns a vector with three elements, which are `&env`, the `symbol` "Hello", and the `symbol` `to`, which is supplied by the invoker of the function. The `&env` parameter is the reference of the Soroban environment, and is not explicitly returned to the user.

```rust
mod test;
```

The last line inserts the code content of the `test.rs` file to the `lib.rs` file.

## Examining the Test

Now, let's examine the `test.rs` file. Examining the tests are important to see how the contract operates. A well tested contract is more secure than a non-tested contract, and security is one of the most important concerns when dealing with contracts on a blockchain.

```rust
#![cfg(test)]

use super::*;
use soroban_sdk::{symbol, vec, Env};

// The purpose of this file is to run automated tests on the 
// contract code we've written in `lib.rs`. Writing tests can be
// quite a big topic, and we'll dive in further in a future quest. 
// Just you wait!
#[test]
fn test() {
    // we register the contract in a Soroban environment, and
    // build a client we can use to invoke the contract
    let env = Env::default();
    let contract_id = env.register_contract(None, HelloContract);
    let client = HelloContractClient::new(&env, &contract_id);

    // Next, we call `client.hello()`, supplying "Dev" as our `to`
    // argument.
    let words = client.hello(&symbol!("Dev"));
    
    // We assert the contract must return a Vec that matches what 
    // we would expect to receive from our contract: 
    // [Symbol("Hello"), Symbol("Dev")]
    assert_eq!(words, vec![&env, symbol!("Hello"), symbol!("Dev"),]);
}
```

The test is also written in Rust, and is used to test the functionality of the `HelloContract` on a local environment.

```rust
#![cfg(test)]

use super::*;
use soroban_sdk::{symbol, vec, Env};
```

The first line configures the file as a test environment. The second line, `use super::*;`, imports everything from the parent module, which is the `HelloContract` file here. As before, the third line imports some implementations from the `soroban_sdk`.

```rust
#[test]
fn test() {
    let env = Env::default();
    let contract_id = env.register_contract(None, HelloContract);
    let client = HelloContractClient::new(&env, &contract_id);

    let words = client.hello(&symbol!("Dev"));
    
    assert_eq!(words, vec![&env, symbol!("Hello"), symbol!("Dev"),]);
}
```

The test implementations are marked with `#[test]`, and allows the Rust compiler to understand that these are testing functions. We start with creating a constant, `env`, and initializing with the default value. Next, we are registering our `HelloContract` to the environment. Now, we have a local Soroban sandbox with only `HelloContract` existing. We then create a client to interact with the contract of ours for testing.

We invoke the function `hello` on our `HelloContract` by using the `hello` method of our client using the "Dev" argument. See that we are not supplying the `env` parameter, as it is implicitly included already. We then set the reply of the function to the `words` constant.

After doing our invocation, we assert the contract must return a `Vec`, which consists of the elements `&env`, "Hello", and our input argument, "Dev". If that is the case, the test ends without an error, which means that our implementation is correct.

> #### Testing Tips
>
> When testing software, we use the AAA (Arrange, Act, and Assert) principle. First, we "Arrange" the environment, which we did here using the first three lines. Then, we "Act" on our source code, which corresponds to invoking our `hello` function on our contract. Finally, we "Assert" that everything is correct by comparing the actual result to the expected result. This way, testing software can be done systematically.

## Compiling, Testing, Deploying

We can compile our code using `cargo build` to compile our rust codes into `.wasm` files. If we want to build only a specific quest's contract, the usage is 

```bash
cargo build --package [package-name] --target wasm32-unknown-unknown --release
```

where the package name of a quest can be found in the `Cargo.toml` file on the quest's folder. For example, the Hello World quest's package name is `soroban-hello-world-contract`, so we can build it using 

```bash
cargo build --package soroban-hello-world-contract --target wasm32-unknown-unknown --release
```

The created object can be found in `target/wasm32-unknown-unknown/release/soroban_hello_world_contract.wasm` file. We can also use `cargo test`, to see if our implementations contains any error.

![Testing Hello World](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/apjrsbt3o8mrjye263pe.png)

Everything looks great! We now can deploy our Soroban contract to the Futurenet using `soroban deploy` command. Please be careful that you are using the `CLI - Futurenet: bash` terminal to successfully accomplish this task. The full command is

```bash
soroban deploy --wasm target/wasm32-unknown-unknown/release/soroban_hello_world_contract.wasm
```

We should see a success message with the contract's ID. If you are getting errors when deploying, wait for the Soroban client to synchronize to the Futurenet, which can take some time. If you are still getting errors, try using the handy command `sq rpc -c` to change the default RPC endpoint to an official one.

![Deploying Soroban Contract](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzx3j9b9iff9i19ovzzr.png)

Great! We will need to supply this ID to interact with our deployed contract. We can use a different contract ID to interact with another contract. The possibilities are endless!

We can now invoke the `hello` function using `soroban invoke` to get a reply from our contract. We should again use the Futurenet CLI for this purpose.

```bash
soroban invoke --id [your contract id] --fn hello --arg [any string argument shorter than 10 characters]
```

The invocation should return a success and the `Vector` that contains the "Hello" word followed by the argument we supplied.

![Soroban Contract Invocation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jibykq7clblot0uc58rt.png)

Everything works perfectly, and we have completed the first quest! Well done! Use `sq check 1` to claim your reward 🎉.

> How Long Will My Contract Live?
>
> Forever! That's the beauty of the blockchains. The immutability and the censorship resistance are what makes blockchains great. This power is a double edged sword though, if we make any mistakes, or have any vulnerabilities in our contract, there's nothing we can do! That's why testing and auditing smart contracts are an important business.
>
> Note that this is the Futurenet, which is a test server for Soroban contracts. It often gets reset, so your Soroban contract will cease to exist. This will not happen when Soroban hits the mainnet!