Skip to main content
The custom types example demonstrates how to define your own data structures that can be stored on the ledger, or used as inputs and outputs to contract invocations. This example is an extension of the storing data example. Open in Codespaces Open in Codeanywhere

Run the Example

First go through the Setup process to get your development environment configured, then clone the v23.0.0 tag of soroban-examples repository:
Or, skip the development environment setup and open this example in GitHub Codespaces or Code Anywhere. To run the tests for the example, navigate to the custom_types directory, and use cargo test.
You should see the output:

Code

custom_types/src/lib.rs
Ref: https://github.com/stellar/soroban-examples/tree/v23.0.0/custom_types

How it Works

Custom types are defined using the #[contracttype] attribute on either a struct or an enum. Open the custom_types/src/lib.rs file to follow along.

Custom Type: Struct

Structs are stored on ledger as a map of key-value pairs, where the key is up to a 32 character string representing the field name, and the value is the value encoded. Field names must be no more than 32 characters.

Custom Type: Enum

The example does not contain enums, but enums may also be contract types. Enums containing unit and tuple variants are stored on ledger as a two element vector, where the first element is the name of the enum variant as a string up to 32 characters in length, and the value is the value if the variant has one. Only unit variants and single value variants, like A and B below, are supported.
Enums containing integer values are stored on ledger as the u32 value.

Using Types in Functions

Types that have been annotated with #[contracttype] can be stored as contract data and retrieved later. Types can also be used as inputs and outputs on contract functions.

Tests

Open the custom_types/src/test.rs file to follow along.
custom_types/src/test.rs
In any test the first thing that is always required is an Env, which is the Soroban environment that the contract will run in.
The contract is registered with the environment using the contract type.
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 IncrementContract, and the client is named IncrementContractClient.
The test invokes the increment function on the registered contract that causes the State type to be stored and updated a couple times.
The test then invokes the get_state function to get the State value that was stored, and can assert on its values.

Build the Contract

To build the contract, use the stellar contract build command.
A .wasm file should be outputted in the target directory:

Run the Contract

If you have stellar-cli installed, you can deploy and invoke contract function.
The following output should occur using the code above.
Run it a few more times with different increment amounts to watch the count change. Use the stellar-cli to inspect what the counter is after a few runs.