sidebar_position | title |
---|---|
1 |
Hello World |
The hello world example demonstrates how to write a simple contract, with a single function that takes one input and returns it as an output.
First go through the Setup process to get your development environment
configured, then clone the v0.0.4
tag of soroban-examples
repository:
git clone -b v0.0.4 https://github.com/stellar/soroban-examples
To run the tests for the example, navigate to the hello_world
directory, and use cargo test
.
cd hello_world
cargo test
You should see the output:
running 1 test
test test::test ... ok
#![no_std]
use soroban_sdk::{contractimpl, symbol, vec, Env, Symbol, Vec};
pub struct HelloContract;
#[contractimpl]
impl HelloContract {
pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
vec![&env, symbol!("Hello"), to]
}
}
Ref: https://github.com/stellar/soroban-examples/tree/v0.0.4/hello_world
Soroban contracts export all public functions that are within impl
blocks that
have been annotated with #[contractimpl]
. In the example above the contract
exports a single function, hello
.
Contract functions must be given names that are no more than 10 characters long.
Open the hello_world/src/lib.rs
file to follow along.
Contract functions must be defined within an impl
block, and therefore a type
is required for the impl to be attached. A simple zero-sized struct can be used.
pub struct HelloContract;
Contract functions look much like regular Rust functions. They mave have any
number of arguments, but arguments must support being transmitted to and from
the Soroban environment that the contract runs in. The Soroban SDK provides some
types like Vec
, Map
, BigInt
, Symbol
, Bytes
, BytesN
, etc that
can be used. Primitive values like u64
, i64
, u32
, i32
, and bool
can
also be used. Floats are not supported.
Contract inputs must not be references.
If the first argument of a contract function is of the soroban_sdk::Env
type,
an Env
will be provided that provides access to additional functionality. Most
functionality within the SDK requires an Env
, so it is recommended to have it
in the argument list for most functions.
#[contractimpl]
impl HelloContract {
pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
...
}
}
Open the hello_world/src/test.rs
file to follow along.
#[test]
fn test() {
let env = Env::default();
let contract_id = BytesN::from_array(&env, &[0; 32]);
env.register_contract(&contract_id, HelloContract);
let client = HelloContractClient::new(&env, &contract_id);
let words = client.hello(&symbol!("SourBun"));
assert_eq!(words, vec![&env, symbol!("Hello"), symbol!("Dev"),]);
}
In any test the first thing that is always required is an Env
, which is the
Soroban environment that the contract will run in.
let env = Env::default();
Contracts must be registered with the environment with a contract ID, which is a 32-byte value.
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 a corresponding function generated in a
generated client type. The client type will be named the same as the contract
type with Client
appended. For example, in our contract the contract type is
HelloContract
, and the client is named HelloContractClient
.
let client = HelloContractClient::new(&env, &contract_id);
let words = client.hello(&symbol!("Dev"));
The values returned by functions can be asserted on:
assert_eq!(words, vec![&env, symbol!("Hello"), symbol!("Dev"),]);
To build the contract, use the cargo build
command.
cargo build --target wasm32-unknown-unknown --release
A .wasm
file should be outputted in the ../target
directory:
../target/wasm32-unknown-unknown/release/soroban_hello_world_contract.wasm
If you have [soroban-cli
] installed, you can invoke contract functions in the
using it.
soroban-cli invoke \
--wasm ../target/wasm32-unknown-unknown/release/soroban_hello_world_contract.wasm \
--id 1 \
--fn hello \
--arg friend
The following output should occur using the code above.
["Hello","friend"]