Complete function signatures, parameters, return types, and error codes for every Soroban contract in this workspace.
Crate: wallet
Source: contracts/wallet/src/lib.rs
Interface: Implements Soroban's CustomAccountInterface (__check_auth).
The wallet is the user's on-chain identity anchor. It holds the registered WebAuthn passkey credentials and delegates policy enforcement to a connected Policy contract.
Registers the first passkey credential. Can only be called once. Typically invoked by the Factory immediately after deployment.
| Parameter | Type | Description |
|---|---|---|
credential_id |
Bytes |
Unique identifier for the WebAuthn credential (e.g. a CBOR-encoded ID from the authenticator) |
public_key |
Bytes |
Uncompressed secp256r1 public key (65 bytes: `04 |
Errors: AlreadyInitialized
Registers an additional passkey credential (e.g. a second device). Requires existing wallet auth.
| Parameter | Type | Description |
|---|---|---|
credential_id |
Bytes |
New credential identifier |
public_key |
Bytes |
Uncompressed secp256r1 public key (65 bytes) |
Auth: env.current_contract_address().require_auth() — must be signed by an existing passkey.
Errors: SignerAlreadyExists
Revokes a registered credential. Refuses to remove the last one (would brick the wallet).
| Parameter | Type | Description |
|---|---|---|
credential_id |
Bytes |
Identifier of the credential to revoke |
Auth: env.current_contract_address().require_auth()
Errors: SignerNotFound, CannotRemoveLastSigner
Guardian-recovery pathway to register a new passkey after device loss. Only callable by the registered Policy contract.
| Parameter | Type | Description |
|---|---|---|
credential_id |
Bytes |
New credential identifier |
public_key |
Bytes |
New uncompressed secp256r1 public key (65 bytes) |
Auth: policy_address.require_auth() — only the wallet's active Policy contract can call this.
Errors: Unauthorized (no policy set), SignerAlreadyExists
Points the wallet at a Policy contract instance.
| Parameter | Type | Description |
|---|---|---|
policy |
Address |
Address of the deployed Policy contract |
Auth: env.current_contract_address().require_auth()
Read-only. Returns all registered credentials as a map of credential_id → public_key.
Called by the Soroban host for every transaction this account authorises. Verifies the WebAuthn signature against a registered passkey.
| Parameter | Type | Description |
|---|---|---|
signature_payload |
Hash<32> |
Hash of the Soroban authorization entry (call, nonce, expiry, network), provided by the host |
signature |
WebAuthnSignature |
{ credential_id: Bytes, authenticator_data: Bytes, client_data_json: Bytes, signature: BytesN<64> } — a full WebAuthn assertion; signature is raw r ‖ s, low-S normalised |
auth_contexts |
Vec<Context> |
Transaction contexts (used for future policy checks) |
Verification steps
- Look up the signer by
credential_id(SignerNotFoundif absent). - Require
client_data_jsonto contain"challenge":"<base64url(signature_payload)>"— binds the passkey assertion to this exact auth entry. msg = SHA-256(authenticator_data ‖ SHA-256(client_data_json))— exactly what the authenticator signed.secp256r1_verify(public_key, msg, signature).
Errors: SignerNotFound, InvalidSignature
Security note: The
signature_payloadis sourced entirely from the Soroban host — it cannot be forged by callers. The SDK enforces this via theHash<32>type restriction.
Crate: factory
Source: contracts/factory/src/lib.rs
Deploys new Wallet contract instances at deterministic, predictable addresses using Soroban's built-in deployer host object.
Stores the WASM hash of the wallet contract that this factory will deploy.
| Parameter | Type | Description |
|---|---|---|
wasm_hash |
BytesN<32> |
SHA-256 hash of the uploaded wallet WASM binary |
Note: Call stellar contract install --wasm wallet.wasm first to upload and get the hash.
Deploys a new wallet contract at a deterministic address and initialises it with the first passkey in a single atomic transaction.
| Parameter | Type | Description |
|---|---|---|
salt |
BytesN<32> |
32-byte salt — unique per wallet. Use a hash of the user's identifier. |
credential_id |
Bytes |
First passkey credential identifier |
public_key |
Bytes |
Uncompressed secp256r1 public key (65 bytes) |
Returns: The Address of the newly deployed wallet contract.
Internal flow:
env.deployer().with_current_contract(salt).deploy(wasm_hash)— deploys the WASMenv.invoke_contract(&wallet_address, "init", (credential_id, public_key))— initialises the wallet
Pure read-only computation of the wallet address that would be deployed for the given salt. No state change, no fees beyond the read cost.
| Parameter | Type | Description |
|---|---|---|
salt |
BytesN<32> |
Same salt you will pass to deploy_wallet |
Returns: The deterministic Address.
UX use case: Call this before deployment so the user can fund their wallet address before they've ever interacted with the network.
Crate: policy
Source: contracts/policy/src/lib.rs
A decoupled, composable rules engine that enforces spend limits, session keys, contract allow-lists, and guardian-based recovery. Attached to a wallet via wallet.set_policy(policy_address).
Initialises the policy with an owner (the wallet contract or a multisig). Can only be called once.
| Parameter | Type | Description |
|---|---|---|
owner |
Address |
The address authorised to configure all policy settings |
Errors: Unauthorized (already initialised)
Configures a rolling spend cap for a specific token.
| Parameter | Type | Description |
|---|---|---|
token |
Address |
The Stellar asset contract address |
amount |
i128 |
Maximum total spend allowed within the window |
window_secs |
u64 |
Rolling window duration in seconds (e.g. 3600 = 1 hour) |
Auth: owner
Errors: — (always succeeds if authorised)
Verifies and records a spend. Called by the wallet's __check_auth before authorising a token transfer.
| Parameter | Type | Description |
|---|---|---|
token |
Address |
Token being spent |
spend_amount |
i128 |
Amount being spent in this transaction |
Errors: SpendLimitExceeded
Rolling window logic: When
current_time >= window_start + window_secs, the accumulator resets. Otherwise amounts are added and checked against the limit.
Issues a time-limited, scope-restricted sub-key for a specific dApp interaction.
| Parameter | Type | Description |
|---|---|---|
session_id |
Bytes |
Unique identifier for this session (client-generated) |
public_key |
Bytes |
secp256r1 public key of the session key (65 bytes) |
scope |
Vec<Address> |
List of contracts this key is allowed to interact with. Empty = all allowed. |
expiry |
u64 |
Unix timestamp after which the key is invalid |
Auth: owner
Immediately invalidates a session key.
| Parameter | Type | Description |
|---|---|---|
session_id |
Bytes |
Identifier of the session to revoke |
Auth: owner
Fetches a session key's metadata if it exists and has not expired.
| Parameter | Type | Description |
|---|---|---|
session_id |
Bytes |
Session identifier |
Returns: SessionKey { public_key, scope, expiry }
Errors: SessionKeyRevoked, SessionKeyExpired
Permits or blocks a specific contract address from being called by this wallet.
| Parameter | Type | Description |
|---|---|---|
target |
Address |
Contract address to allow or block |
allowed |
bool |
true to permit, false to block |
Auth: owner
Enables or disables the allow-list feature entirely. When disabled, no contract filtering is applied.
| Parameter | Type | Description |
|---|---|---|
enabled |
bool |
true to enforce allow-list, false to disable |
Auth: owner
Checks whether the target is permitted. A no-op when allow-lists are disabled.
| Parameter | Type | Description |
|---|---|---|
target |
Address |
Contract address being checked |
Errors: NotAllowListed
Adds or removes a guardian address from the recovery set.
| Parameter | Type | Description |
|---|---|---|
guardian |
Address |
Guardian's Stellar address |
Auth: owner
Sets the N in N-of-M — how many guardians must approve a recovery.
| Parameter | Type | Description |
|---|---|---|
threshold |
u32 |
Minimum approvals required (default: 2) |
Auth: owner
Sets the delay between reaching threshold and execution.
| Parameter | Type | Description |
|---|---|---|
delay_secs |
u64 |
Delay in seconds (recommended: 172800 = 48h testnet, 604800 = 7d mainnet) |
Auth: owner
A guardian proposes replacing the wallet's signer with a new passkey.
| Parameter | Type | Description |
|---|---|---|
caller |
Address |
The proposing guardian (must be registered) |
new_credential_id |
Bytes |
Replacement passkey credential identifier |
new_public_key |
Bytes |
Replacement uncompressed secp256r1 public key |
Returns: proposal_id: u64
Auth: caller.require_auth() + must be a registered guardian
Errors: InvalidGuardian
A second (or subsequent) guardian co-signs an active proposal.
| Parameter | Type | Description |
|---|---|---|
caller |
Address |
The approving guardian |
proposal_id |
u64 |
ID returned by propose_recovery |
Auth: caller.require_auth() + must be a registered guardian
Errors: InvalidGuardian, ProposalNotFound, ProposalNotActive, AlreadyApproved
Finalises an approved, timelocked recovery. Callable by anyone once conditions are met.
| Parameter | Type | Description |
|---|---|---|
wallet |
Address |
The wallet contract to rotate the signer on |
proposal_id |
u64 |
ID of the proposal to execute |
Errors: ProposalNotFound, ProposalNotActive, NotEnoughApprovals, TimelockNotExpired
On success: Calls wallet.recover_signer(new_credential_id, new_public_key).
| Code | Name | When thrown |
|---|---|---|
1 |
NotInitialized |
Wallet function called before init |
2 |
AlreadyInitialized |
init called more than once |
3 |
InvalidSignature |
secp256r1 signature verification failed |
4 |
SignerNotFound |
Credential ID not registered |
5 |
SignerAlreadyExists |
Credential ID already registered |
6 |
Unauthorized |
Caller lacks required auth |
7 |
PolicyCallFailed |
Policy contract returned an error |
8 |
CannotRemoveLastSigner |
Attempt to remove the only signer |
| Code | Name | When thrown |
|---|---|---|
1 |
NotInitialized |
Policy function called before init |
2 |
Unauthorized |
Caller lacks owner auth |
3 |
SpendLimitExceeded |
Spend would exceed rolling cap |
4 |
SessionKeyExpired |
Session key timestamp is past expiry |
5 |
SessionKeyWrongScope |
Target contract not in session key scope |
6 |
SessionKeyRevoked |
Session key has been removed |
7 |
SessionKeyInvalidSignature |
Session key secp256r1 verification failed |
8 |
NotAllowListed |
Target contract not in allow-list |
9 |
InvalidGuardian |
Caller is not a registered guardian |
10 |
ProposalNotFound |
Recovery proposal ID does not exist |
11 |
AlreadyApproved |
Guardian already approved this proposal |
12 |
TimelockNotExpired |
Timelock delay has not elapsed yet |
13 |
NotEnoughApprovals |
Fewer approvals than threshold |
14 |
ProposalNotActive |
Proposal already executed or cancelled |