Address pointing at this contract instance is used, the logic defined here runs through the Soroban auth framework.
Contract accounts are exclusive to Soroban and can’t be used to perform other Stellar operations.
Implementing a contract account requires a very good understanding of authentication and authorization and requires rigorous testing and review. The example here is not a full-fledged account contract - use it as an API reference only.
Run the Example
First go through the Setup process to get your development environment configured, then clone thev23.0.0 tag of soroban-examples repository:
cargo test.
How it Works
Open theaccount/src/lib.rs file to follow along.
Account contracts implement a special function __check_auth that takes the signature payload, signatures and authorization context. The function should error if auth is declined, otherwise auth will be approved.
This example contract uses ed25519 keys for signature verification and supports multiple equally weighted signers. It also implements a policy that allows setting per-token limits on transfers. The token can be spent beyond the limit only if every signature is provided.
For example, the user may initialize this contract with 2 keys and introduce 100 USDC spend limit. This way they can use a single key to sign their contract invocations and be sure that even if they sign a malicious transaction they won’t spend more than 100 USDC.
Initialization
account/src/lib.rs
Policy modification
require_auth can be used for the current_contract_address(), i.e. the account contract may be used to verify authorization for its own administrative functions. This way there is no need to write duplicate authorization and authentication logic.
__check_auth
__check_auth is a special function that account contracts implement. It will be called by the Soroban environment every time require_auth or require_auth_for_args is called for the address of the account contract.
Here it is implemented in two steps. First, authentication is performed using the signature payload and a vector of signatures. Second, authorization policy is enforced using the auth_context vector. This vector contains all the contract calls that are being authorized by the provided signatures.
__check_auth is a reserved function and can only be called by the Soroban environment in response to a call to require_auth. Any direct call to __check_auth will fail. This makes it safe to write to the account contract storage from __check_auth, as it’s guaranteed to not be called in unexpected context. In this example it’s possible to persist the spend limits without worrying that they’ll be exhausted via a bad actor calling __check_auth directly.
Authentication
Authorization policy
Context. i.e. per one require_auth call for the address of this account. The policy for the account contract itself enforces every signer to have signed the method call.
Tests
Open theaccount/src/test.rs file to follow along.
Refer to another examples for the general information on the test setup.
Here we only look at some points specific to the account contracts.
Address, account contracts deal with the signature verification and hence need to actually sign the payloads.
__check_auth can’t be called directly as regular contract functions, hence we need to use try_invoke_contract_check_auth testing utility that emulates being called by the Soroban host during a require_auth call.
try_invoke_contract_check_auth allows verifying the exact error code and makes sure that the verification has failed due to not having enough signers and not for any other reason.
It’s a good idea for the account contract to have detailed error codes and verify that they are returned when they are expected.
Further Reading
- Delegate Auth example — extends this example with CAP-71 auth delegation to registered delegate signers.