Skip to content

Commit

Permalink
Add more getting started documentation (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmcculloch authored Jul 29, 2022
1 parent f5d216e commit 666cb2d
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 44 deletions.
16 changes: 16 additions & 0 deletions docs/getting-started/build-a-wasm-file.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
sidebar_position: 6
title: Build a WASM File
---

To build a Soroban contract into a `.wasm` file, use the `cargo build` command.

```sh
cargo build --target wasm32-unknown-unknown --release
```

A `.wasm` file should be outputted in the `target` directory:

```
target/wasm32-unknown-unknown/release/[project-name].wasm
```
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
sidebar_position: 4
title: Building Optimized WASM
sidebar_position: 8
title: Build an Optimized WASM File
---

import Tabs from '@theme/Tabs';
Expand Down
42 changes: 0 additions & 42 deletions docs/getting-started/install-soroban-cli.mdx

This file was deleted.

28 changes: 28 additions & 0 deletions docs/getting-started/run-a-wasm-file.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
sidebar_position: 7
title: Run a WASM File
---

If you have [`soroban-cli`] installed, you can invoke contract functions in a
WASM file.

Using the code we wrote in [Write a Contract](write-a-contract.mdx) and the the
resulting `.wasm` file we built in [Build a WASM File](build-a-wasm-file.mdx)
run the following command to invoke the `hello` function with a single argument
`"friend"`.

```sh
soroban-cli invoke \
--file target/wasm32-unknown-unknown/release/first-project.wasm \
--contract-id 1
--fn hello
--arg friend
```

The following output should appear.

```
["Hello","friend"]
```

[`soroban-cli`]: install-soroban-cli.mdx
41 changes: 41 additions & 0 deletions docs/getting-started/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,46 @@ Many editors have support for Rust. Visit the following link to find out how to
configure your editor:
https://www.rust-lang.org/tools

## Install Soroban CLI

The Soroban CLI can execute WASM contracts in the same environment the contract
will execute on network, however in a local sandbox.

Install the Soroban CLI using `cargo install`.

```sh
cargo install --locked --git http://github.com/stellar/soroban-cli soroban-cli
```

:::caution
The `soroban-cli` is still in early development. Please report issues
[here](https://github.com/stellar/soroban-cli).
:::

### Usage

Run the `soroban-cli` command and you should see output like below.

```sh
soroban-cli
```

```
soroban-cli 0.0.1
USAGE:
soroban-cli <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
invoke Invoke a contract function in a WASM file
inspect Inspect a WASM file listing contract functions, meta, etc
deploy Deploy a WASM file as a contract
version Print version information
```


[Rust]: https://www.rust-lang.org/
[Soroban CLI]: install-soroban-cli.mdx
97 changes: 97 additions & 0 deletions docs/getting-started/testing.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
sidebar_position: 5
title: Testing
---

Writing tests for Soroban contracts involves writing Rust code using the Rust
test facilitiaties and toolchain that you'd use for testing any Rust code.

Given a simple contract like the contract demonstrated in [Write a
Contract](write-a-contract.mdx).

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

pub struct Contract;

#[contractimpl(export_if = "export")]
impl Contract {
pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
const GREETING: Symbol = Symbol::from_str("Hello");
vec![&env, GREETING, to]
}
}
```

A simple test will look like this.

```
#[cfg(test)]
mod test {
use super::{Contract, hello};
use soroban_sdk::{vec, Env, FixedBinary};
#[test]
fn test() {
let env = Env::default();
let contract_id = FixedBinary::from_array(&env, [0; 32]);
env.register_contract(&contract_id, Contract);
let words = hello::invoke(&env, &contract_id, &Symbol::from_str("Dev"));
assert_eq!(
words,
vec![&env, Symbol::from_str("Hello"), Symbol::from_str("Dev"),]
);
}
}
```

In any test the first thing that is always required is an `Env`, which is the
Host environment that the contract will run it.

```rust
let env = Env::default();
```

Contracts must be registered with the environment with a contract ID, which is a
32-byte value. In many cases it is sufficient to use a simple zero ID, however
if the test will deploy the contract multiple times, or deploy multiple
contracts, each should use their own IDs.

```rust
let contract_id = FixedBinary::from_array(&env, [0; 32]);
env.register_contract(&contract_id, HelloContract);
```

All public functions within an `impl` block that is annotated with the
`#[contractimpl]` attribute have an `invoke` function generated, that can be
used to invoke the contract function within the environment.

```rust
let words = hello::invoke(&env, &contract_id, &Symbol::from_str("SourBun"));
```

The values returned by functions can be asserted on:
```rust
assert_eq!(
words,
vec![&env, Symbol::from_str("Hello"), Symbol::from_str("SourBun"),]
);
```

## Run the Tests

Run `cargo test` and watch the contract run. You should see the following output:

```sh
cargo test
```

```
running 1 test
test test::test ... ok
```

Try changing the values in the test to see how it works.
64 changes: 64 additions & 0 deletions docs/getting-started/write-a-contract.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
sidebar_position: 4
title: Write a Contract
---

Once you have a project setup, like how we setup a project in [First
Project](first-project.mdx), writing a contract involves writing Rust code in
the projects `lib.rs` file.

```rust
#![no_std]
```

All contracts should begin with `#![no_std]` to ensure that the Rust standard
library is not included in the build. The Rust standard library is large and not
well suited to being deployed into small programs like those deployed to
blockchains.

```rust
use soroban_sdk::{contractimpl, vec, Env, Symbol, Vec};
```

The contract will need to import the types and macros that it needs from the
`soroban_sdk` crate. Take a look at [First Project](first-project.mdx) to see
how to setup a project.

Many of the types available in typical Rust programs, such as `std::vec::Vec`,
are not available, as their is no allocator and no heap memory in Soroban
contracts. The `soroban_sdk` provides a variety of types like `Vec`, `Map`, and
`BigInt`, `Binary`, `FixedBinary`, that all utilize the Host environments memory
and native capabilities.

```rust
pub struct Contract;

#[contractimpl(export_if = "export")]
impl Contract {
pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
todo!()
}
}
```

Contract functions live inside a `impl` for a struct. The `impl` block is
annotated with `#[contractimpl]`, and the functions that are intended to be
called are assigned `pub` visibility and have an `Env` argument as their first
argument.

Putting those pieces together a simple contract will look like this.

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

pub struct Contract;

#[contractimpl(export_if = "export")]
impl Contract {
pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
const GREETING: Symbol = Symbol::from_str("Hello");
vec![&env, GREETING, to]
}
}
```

0 comments on commit 666cb2d

Please sign in to comment.