Advanced contract account patterns
Use these patterns to extend a basic contract account with guardrails. Put the logic in __check_auth or a helper it calls, and test both the allow and deny paths. Treat signer rules as “who can act” and policy rules as “under what conditions.”
Spend limits
- Store a limit and a running total in instance storage (for example, outflows over the last 24 hours).
- Derive a window key from the ledger timestamp (for example,
day = timestamp / 86_400) and reset the total when the window changes. - On each request, check the remaining allowance; if the amount would exceed it, reject and emit an event with the attempted amount and remaining allowance.
See the Complex Account example for a reference implementation with weighted signers and limits.
Allow lists
- Keep allowed destination addresses or contract IDs in storage.
- Inspect both the root invocation and any subinvocations in
auth_contextbefore approving so nested calls cannot bypass the list.
Policy signers
- Define one or more policy signer roles in storage. A policy signer exists to approve or deny specific actions (for example, an auditor key, a guardian key, or a service that enforces spending rules).
- For high-risk contract calls (e.g. large transfers, changing signers), require the end user plus a policy signer; reject if either is missing.
- Separate roles (admin vs. standard) so daily use can be delegated while upgrades or recovery stay with admins.
Time rules
- Block execution until a specific ledger timestamp, or add a cooldown after actions like key rotation or large transfers.
- Store the earliest allowed timestamp in instance storage; compare it against the current ledger timestamp in
__check_auth.
Session keys
- Generate a short-lived session key (for example, a p256 key created client-side and kept in secure browser storage) and limit it to one function plus a maximum amount.
- Store a record for the session key with its expiry, allowed scope, and remaining allowance; reduce the allowance on each authorized call.
- Reject if the session key is unknown, expired, out of allowance, or used outside its allowed scope.
External policy contracts
- Offload specific checks (deny lists, time windows, device posture) to a dedicated policy contract; pass context into
__check_authand require the policy contract to approve before returning success. - Keep the policy interface minimal (for example,
fn approve(auth_context) -> bool) so you can swap policies without changing your account.
Where to go next
- See these patterns applied in the contract account examples.
- Explore reference implementations and libraries:
Guides in this category:
Smart wallets
Smart wallets are contract accounts that act as user wallets. They hold assets and enforce authorization in check_auth instead of a single secret key. Passkeys (WebAuthn) are common, but you can also use Ed25519 keys, policy signers, session keys or anything the contract can verify.
Advanced contract account patterns
Layer spend limits, allow lists, time rules, and other guardrails onto contract accounts.
Contract account examples
Real projects that showcase policy signers, passkeys, and contract-account UX on Stellar.