Skip to main content
Using Cargo’s workspace feature makes it very convenient to organize your smart contracts in subdirectories of your project’s root. It’s very simple to get started using the cli:
Running this command will create a root project directory (soroban-project) and then initialize a project workspace with a single contract named add_contract. Adding one more contract template to the project can be done using the same command:
The project tree in the soroban-project directory will look like this:
Running stellar contract init command created a new contract, located in ./contracts, each containing:
  • Cargo.toml file with the soroban-sdk dependency
  • src directory with an example hello-world contract and a test.
Build the contracts with the following command (don’t forget to change working directory to soroban-project first before running it), and check the build directory target/wasm32v1-none/release/ for the compiled .wasm files.

Integrating Contracts in the Same Workspace

With the given project structure, cross-contract calls can be easily made. Starting with modifying the sample hello world contract into an add contract:
contracts/add_contract/src/lib.rs
In this tutorial we use workspaces to import contract client. However, it’s also possible to use contract’s compiled code instead (for example, if you don’t have a source code for it). See making cross-contract calls guide for more info
Next, in order to call ContractAdd from another contract, it’s necessary to add a workspace dependency:
./contracts/main_contract/Cargo.toml
The ContractAdd can now be referenced and used from another contracts using ContractAddClient:
contracts/main_contract/src/lib.rs
Here, main contract will invoke ContractAdd’s add function to calculate the sum of 2 numbers. It’s a good idea to update tests for our main contract as well:
contracts/main_contract/src/test.rs
Contracts can now be re-complied running the following command from the project root:
And check that the test is working correctly, running tests in contracts/main_contract:
Finally, let’s deploy this contracts and call our main contract using cli. If you haven’t already, set up an account (alice) first
Second is to deploy the contracts:
And finally call the main contract:

Adding contract interfaces

As the next step, we can abstract away add contract and allow it to have multiple implementations. Main contract will in turn use the contract interface that is not bound to its implementation.
First, let’s create an interface and change our existing implementation to use this interface:
contracts/adder_interface/src/lib.rs
To use the interface definition our workspace members will now have an adder_interface as a dependency:
./Cargo.toml
./contracts/add_contract/Cargo.toml
./contracts/main_contract/Cargo.toml
./contracts/add_extra_contract/Cargo.toml
And change lib type of adder_interface crate:
./contracts/adder_interface/Cargo.toml
./contracts/adder_interface/src/lib.rs
contracts/add_contract/src/lib.rs
contracts/main_contract/src/lib.rs
As the final step we can create an alternative Adder implementation that adds an extra 1:
contracts/add_extra_contract/src/lib.rs
We can now deploy this contracts and test the new behavior:
Now let’s try to do sum 2 unsigned integers causing an overflow: