- Other Rust crates can be used (provided that they are compatible with Soroban’s Rust dialect);
- Other smart contract can be used. This is referred to as a cross-contract call.
Contract as a dependency
While finding a contract is out of scope for this guide, there are a few places to be on the lookout. Most projects and dApps publicly disclose the address of their Stellar smart contract on their website. With this information, a block explorer is a powerful tool to understand how a contract is being used. Some explorers also allow you to download the compiled contract as a Wasm file. There are also projects that provide a link to access the code itself.Contract addressTo depend on a project, we need to know the contract address of the contract to depend on.
Public API
All public functions of a contract can be called. Using a network explorer can be helpful as some allow you to see the Rust interface of a contract. Bindings can also be generated using the CLI:Making a cross-contract call
Once we know which function to call and which arguments to use, there are two main ways to make a cross-contract call: we can either manually invoke the contract or use a contract client. Let’s start by manually invoking the contract using only a contract’s address. In this example, we have an external contract with a public function namedadd_with which takes two u32 as input values to sum them.
Val.
If we want more tools to help us, we need to get access to a contract client. A common way to do this is to load the Wasm of a contract using contractimport!. This allows us to pass normal types without needing manual conversions from our side. Behind the scenes, this way of doing it is simply a convenient wrapper around env.invoke_contract.
Handling responses
In the examples above, we have usedenv.invoke_contract and client.some_function. In both cases, if there is an issue with the underlying contract call, the contract will panic. This might be a valid approach, but in some cases we want to catch errors and handle them depending on the outcome. This allows you to forward a custom error message, or even trigger an alternative code path.
Enter try_. By using env.try_invoke_contract or client.try_some_function, most underlying errors won’t make the contract panic. Instead, errors will be wrapped and can be handled. For example if we wanted to default to 0 in case of an error:
match statement:
Depending on another contract
Congratulations, now you can effectively leverage the whole Soroban ecosystem and its myriad of smart contracts. There is one last point to discuss before closing up: dependability. As with calling any smart contract, depending on an external smart contract should be done with care. It is advisable to do your own research and analysis on the contract you want to use. As contracts can be updated without their address changing, it is important to pay close attention to any changes in the underlying code. Besides this security consideration, upgrading a contract is an integral part of a contract’s lifecycle. New features are added, bugs are fixed, and public API changes are made. Here as well, it is important to observe any development on these contracts to ensure the continuous operation of your own contract.Examples
See the following full example with tests:- Cross-contract calls shows how to create two contracts, deploy them, and then how to call one from the other.