A comprehensive smart contract system for Stellar/Soroban that provides enterprise-grade account management with multi-signature support, role-based access control, and policy-based authorization. Designed for both human users and AI agents requiring sophisticated permission systems.
- π Multi-Signature Account: Advanced smart account with customizable authentication
- π Contract Factory: Permissionless deployment system with deterministic addresses
- π― Role-Based Permissions: Admin and Standard signer roles with optional policies
- π Policy System: External delegation, token spending limits with reset windows and recipient allowlists, and extensible policies
- π Plugin System: Extensible architecture with install/uninstall lifecycle and authorization hooks
- π External Delegation: Delegate authorization decisions to external policy contracts
- π€ AI Agent Ready: Built for both human users and automated systems
- β‘ Soroban Native: Leverages Stellar's smart contract platform capabilities
- π Upgradeable: Built-in contract upgrade support with permission controls
- π V1βV2 Migration: Built-in migration system for upgrading from v1 contracts
The system consists of multiple smart contracts and shared libraries:
stellar-smart-account/
βββ contracts/
β βββ smart-account/ # Multi-signature account contract with plugin support
β βββ smart-account-interfaces/ # Shared types and trait definitions
β βββ contract-factory/ # Permissionless contract deployment factory
β βββ examples/
β β βββ plugin-policy-example/ # Example plugin+policy contract
β β βββ plugin-policy-example-reverts/ # Example plugin that reverts on uninstall
β βββ initializable/ # Contract initialization utilities
β βββ storage/ # Storage management utilities
β βββ testing/ # Shared test utilities
β βββ upgradeable/ # Contract upgrade utilities
β βββ web-auth/ # WebAuthn verification utilities
The core smart account provides:
- Multiple Signature Schemes: Ed25519, Secp256r1, WebAuthn (passkeys), and Multisig (M-of-N threshold), extensible to others
- Flexible Authorization: Role-based access with policy enforcement
- Multi-Signature Support: Customizable authorization logic
- Plugin Architecture: Extensible functionality through installable plugins
- External Delegation: Delegate authorization to external policy contracts
- Soroban Integration: Native account interface implementation
Permissionless deployment system featuring:
- Open Deployment: Anyone can deploy smart account contracts
- Deterministic Addresses: Predictable contract addresses using salt values
- Idempotent Deploys: Safe re-deployment attempts return existing addresses
- Rust 1.75+ with
wasm32-unknown-unknowntarget - Stellar CLI
- Clone the repository:
git clone https://github.com/Crossmint/stellar-smart-account.git
cd stellar-smart-account- Build the contracts:
stellar contract build- Run tests:
cargo test| Role | Capabilities | Use Cases |
|---|---|---|
| Admin | Full access, can upgrade contracts | System administrators, emergency access |
| Standard | Normal operations, cannot modify signers, optional policy restrictions | Regular users, application accounts, AI agents with policies |
- External Delegation: Delegate authorization decisions to external policy contracts
- Token Transfer Policy: Restrict signers to specific token transfers with cumulative spending limits, reset windows, recipient allowlists, and per-policy expiration
- Extensible: Add custom policies by implementing the
AuthorizationCheckandPolicyCallbacktraits
Standard signers can have an expiration timestamp. Once the ledger timestamp exceeds the expiration, the signer is rejected. A value of 0 means no expiration.
// Create an AI agent with time-limited access using signer expiration
let ai_signer = Signer::Ed25519(
Ed25519Signer::new(ai_agent_pubkey),
SignerRole::Standard(None, end_timestamp) // expires at end_timestamp, 0 = no expiration
);// Delegate authorization to an external policy contract
let external_policy = ExternalPolicy {
policy_address: deny_list_contract_address,
};
let restricted_signer = Signer::Ed25519(
Ed25519Signer::new(signer_pubkey),
SignerRole::Standard(
Some(vec![SignerPolicy::ExternalValidatorPolicy(external_policy)]),
0, // 0 = no expiration
)
);// Initialize smart account with plugins
SmartAccount::__constructor(
env,
vec![admin_signer],
vec![analytics_plugin_address, logging_plugin_address]
);
// Install additional plugins after deployment
SmartAccount::install_plugin(&env, new_plugin_address)?;Run the full test suite:
# Run all tests
cargo test
# Run with coverage
cargo install cargo-tarpaulin
cargo tarpaulin --out HtmlFor optimal performance and cost on Soroban, this project uses storage types deliberately:
- Persistent storage: durable, TTL-based entries with rent; best for long-lived, potentially larger datasets
- Instance storage: bundled with the contract entry, automatically loaded each call; best for small data needed on most calls
- Temporary storage: short TTL and cheaper rent; not used here for critical state
Applied to the Smart Account:
- Signers (SignerKey -> Signer): Persistent
- Admin count (ADMIN_COUNT_KEY): Persistent
- Plugins registry (PLUGINS_KEY): Instance (invoked on every __check_auth)
- Migration flag (MIGRATING): Instance
Why this mapping:
- Plugins are accessed on every call in __check_auth, so keeping the plugin registry in Instance storage avoids separate persistent reads on each invocation.
- Signers and admin count are long-lived and can grow; storing them in Persistent avoids growing the contract instance entry and respects durability expectations.
Notes:
- Instance storage is limited by the ledger entry size limit (approximately 128 KB for the contract entry), so only small, frequently accessed data should be kept there.
- Persistent entries accrue rent over time and can be restored after archival if TTL expires by paying a fee.
Potential future optimizations (not implemented here):
- Skip plugin callbacks when auth contexts are clearly unrelated
- Maintain a fast βhas_pluginsβ indicator to early-exit
- Track a subset of βauth-hookβ plugins to invoke only those on __check_auth
The project maintains 80%+ test coverage with comprehensive integration tests.
- Define the signer struct in
contracts/smart-account-interfaces/src/auth/types.rs - Implement the
SignatureVerifiertrait incontracts/smart-account/src/auth/signers/ - Add variants to
SignerKeyandSignerenums in the interfaces crate, andSignerProofincontracts/smart-account/src/auth/proof.rs - Add a
From<NewSigner> for SignerKeyimplementation - Update match statements in
contracts/smart-account/src/auth/signer.rsandcontracts/smart-account/src/auth/core/authorizer.rs
- Create the policy struct in
contracts/smart-account-interfaces/src/auth/types.rs - Implement
AuthorizationCheckandPolicyCallbacktraits incontracts/smart-account/src/auth/policy/AuthorizationCheck::is_authorized(&self, env, signer_key, contexts) -> boolPolicyCallback::on_add(&self, env, signer_key) -> Result<(), SmartAccountError>PolicyCallback::on_revoke(&self, env, signer_key) -> Result<(), SmartAccountError>
- Add a variant to the
SignerPolicyenum in the interfaces crate - Update match arms in
contracts/smart-account/src/auth/permissions.rs
See the Smart Account Architecture Documentation for detailed extension guides.
The contracts are designed for deployment on:
- Stellar Testnet: For development and testing
- Stellar Futurenet: For experimental features
- Stellar Mainnet: For production deployments
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Ensure tests pass:
cargo test - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
