Contract b485f817469402ba4ccc24ea30077308f69589cbe0897db49087b15f58659ea5

← Back to Index 📥 Download WASM

Meta

rssdkver 22.0.11#34f7f53ae31e0fd02aab436a9872e79fa671ca02
rsver 1.85.0

Instances

  • CABCH3GZPGJOOZXPLN4EBXTLZSV6BUGFBXIKMNO2VJIPZ7ERENL7PCJ7
  • CARM3RKO7MDAHVAR7RP3AEMO2GXVHRLA5FSEZD5OE2WARCADCEKGDK62
  • CBLW7QHWAO2PSS52ZUMQCRWX7XPR63MXZAGJFGIL3JUA6XFAITPIE33H
  • CCGIA4C7CGUARBWOOY6G2J7FRE6QT77AECCJTOEDQ3SAIWFPFNT55BKK
  • CD56UXUGA6CI7G27UGG23Z6BWYXBHJJOJN7SDF2GFYZWTUMUFZUU6JKJ
  • CDABRP5CQNADZKSDVERG42HNE2BVQFFI2BVADHPLQV3JOPZNPBFZTLYD
  • CDUS5S3AENE5QREEHCIEHGKMP6LMBDELUYB35ZSFYETXETN2674MXQHK

Interface

Initialise the wallet with its first signer and domain-binding parameters.

rp_id - the WebAuthn relying party ID (e.g. "localhost" for dev, "veil.app" for production). Must match the domain that serves the frontend. Keep it configurable - do not hardcode.

origin - the exact WebAuthn origin (e.g. "https://veil.app"). Must match the origin field the browser embeds in every clientDataJSON for this deployment.

fn init(
    env: soroban_sdk::Env,
    initial_signer: soroban_sdk::BytesN<65>,
    rp_id: soroban_sdk::Bytes,
    origin: soroban_sdk::Bytes,
) -> Result<(), WalletError>

Add a new signer key to the wallet. Requires authorization from the contract itself (i.e. an existing signer must authorize via __check_auth). Returns the index assigned to the new signer.

fn add_signer(env: soroban_sdk::Env, new_public_key: soroban_sdk::BytesN<65>) -> u32

Remove a signer by index. Requires authorization from the contract. Rejects removal if it would leave the wallet with zero signers.

fn remove_signer(env: soroban_sdk::Env, index: u32) -> Result<(), WalletError>

Atomically replace a registered signer key (old_public_key) with a new one (new_public_key) — the device-rotation flow for a lost or replaced passkey.

Requires authorization from the contract itself, so an existing signer must authorize the call via __check_auth. This means only the current owner can rotate the key: a lost device cannot be silently swapped out by a third party.

The new key takes over the same index as the old one, so the signer set size is unchanged and — critically — the wallet's contract address and balances are untouched. No redeploy is needed.

Errors:

  • InvalidPublicKey — old and new are the same key (no-op).
  • SignerAlreadyExists — new_public_key is already registered.
  • SignerNotFound — old_public_key is not a registered signer.
fn rotate_signer(
    env: soroban_sdk::Env,
    old_public_key: soroban_sdk::BytesN<65>,
    new_public_key: soroban_sdk::BytesN<65>,
) -> Result<(), WalletError>

Called by the Soroban runtime to authorize a transaction.

Three credential branches are handled, tried in order:

Branch 1 — Allowance (spender Address) signature is an Address. The spender presents itself and the on-chain allowance record is debited. No cryptographic work needed because spender.require_auth() already verified the spender's sig.

Branch 2 — Session key Vec<Val>[key_id, ed25519_sig, nonce] signature is a Vec<Val> with exactly 3 elements: [0] BytesN<32> — key_id (storage lookup handle, NOT a secret) [1] BytesN<64> — ed25519 signature of signature_payload [2] u64 — current contract nonce (replay binding)

Authorization requires:

  1. An ed25519 signature over signature_payload that verifies against the public key registered in the ACL for key_id. The key_id is public; possession of it is NOT sufficient — the holder must produce a fresh signature on the host-provided payload for every call.
  2. The submitted nonce matches the on-chain nonce (contr
fn __check_auth(
    env: soroban_sdk::Env,
    signature_payload: soroban_sdk::BytesN<32>,
    signature: soroban_sdk::Val,
    _auth_contexts: soroban_sdk::Vec,
) -> Result<(), WalletError>

Return the current monotonic nonce for this wallet.

fn get_nonce(env: soroban_sdk::Env) -> u64
fn has_signer(env: soroban_sdk::Env, key: soroban_sdk::BytesN<65>) -> bool
fn get_signers(env: soroban_sdk::Env) -> soroban_sdk::Map>
fn execute(
    env: soroban_sdk::Env,
    target: soroban_sdk::Address,
    func: soroban_sdk::Symbol,
    args: soroban_sdk::Vec,
)

Set spending limit for a specific token and spender.

Requires passkey authorization (i.e. from the contract itself).

fn approve(
    env: soroban_sdk::Env,
    spender: soroban_sdk::Address,
    token: soroban_sdk::Address,
    amount: i128,
    expiry: Option,
)

Get the current allowance for a spender and token.

fn get_allowance(
    env: soroban_sdk::Env,
    spender: soroban_sdk::Address,
    token: soroban_sdk::Address,
) -> Option

Set or update the guardian address for this wallet.

Only callable by the current wallet signer (authenticated via __check_auth). The guardian is authorized to initiate key recovery if the signer key is lost.

Arguments

  • env - The Soroban environment handle.
  • guardian - The Address of the new guardian.
fn set_guardian(env: soroban_sdk::Env, guardian: soroban_sdk::Address)

Initiate a guardian recovery to replace the wallet signer key.

Only callable by the designated guardian. Records the new public key and starts a timelock countdown. After the timelock expires, complete_recovery can be called to finalize the key replacement.

Arguments

  • env - The Soroban environment handle.
  • new_public_key - The 65-byte uncompressed public key of the new signer.

Errors

  • WalletError::NoGuardianSet - if no guardian has been configured.
  • WalletError::RecoveryAlreadyPending - if a recovery is already in progress.
fn initiate_recovery(
    env: soroban_sdk::Env,
    new_public_key: soroban_sdk::BytesN<65>,
) -> Result<(), WalletError>

Complete a pending guardian recovery after the timelock has expired.

This function is permissionless - anyone can call it once the timelock has expired. It replaces the wallet signer with the new public key that was specified during initiate_recovery.

Errors

  • WalletError::RecoveryNotPending - if no recovery has been initiated.
  • WalletError::RecoveryTimelockActive - if the timelock has not yet expired.
fn complete_recovery(env: soroban_sdk::Env) -> Result<(), WalletError>

Cancel a pending guardian recovery.

Only callable by the current wallet signer (the contract itself must authorize). This allows a wallet owner who still has their key to abort an unwanted or malicious recovery attempt.

Errors

  • WalletError::RecoveryNotPending - if no recovery has been initiated.
fn cancel_recovery(env: soroban_sdk::Env) -> Result<(), WalletError>

Register a scoped session key with an ACL.

The caller must supply the ed25519 public key (pubkey) of the session key holder in addition to the key_id storage handle. Every future __check_auth call using this key must carry an ed25519 signature of signature_payload produced by the corresponding private key.

Requires wallet owner authorization (existing signer via __check_auth).

fn register_session_key(
    env: soroban_sdk::Env,
    pubkey: soroban_sdk::BytesN<32>,
    key_id: soroban_sdk::BytesN<32>,
    target_contract: soroban_sdk::Address,
    selector: soroban_sdk::Symbol,
    amount_cap: i128,
    expiry: u64,
)

Immediately revoke a session key. Requires the wallet owner to authorize.

fn revoke_session_key(env: soroban_sdk::Env, key_id: soroban_sdk::BytesN<32>)

Set a 24-hour rolling spend limit for a WebAuthn signer key.

Once set, every __check_auth call using key_id sums all context amounts and checks the total against cap within a rolling 24-hour window. Pass cap = 0 to block all spending. Call remove_key_spend_limit to lift the restriction entirely.

Requires wallet owner authorization.

fn set_key_spend_limit(
    env: soroban_sdk::Env,
    key_id: soroban_sdk::BytesN<65>,
    cap: i128,
)

Remove the 24-hour spend limit for a signer key (no limit = no cap).

Requires wallet owner authorization.

fn remove_key_spend_limit(env: soroban_sdk::Env, key_id: soroban_sdk::BytesN<65>)

Get the current spend window record for a signer key, if any.

fn get_key_spend_limit(
    env: soroban_sdk::Env,
    key_id: soroban_sdk::BytesN<65>,
) -> Option

Register a designated recovery key for this wallet.

The recovery key is an Address (e.g. a cold-wallet account) that is authorized to initiate signer rotation via request_recovery. Requires current wallet signer authorization.

fn set_recovery_key(env: soroban_sdk::Env, key: soroban_sdk::Address)

Start a 7-day recovery cooldown to replace the active signer.

Only the designated recovery key (set via set_recovery_key) may call this. After the 7-day timelock expires, anyone can call finalize_recovery to complete the rotation.

Errors

  • NoRecoveryKeySet — no recovery key has been registered.
  • RecoveryAlreadyPending — a recovery request is already in progress.
fn request_recovery(
    env: soroban_sdk::Env,
    new_signer: soroban_sdk::BytesN<65>,
) -> Result<(), WalletError>

Finalize a pending recovery request after the 7-day timelock has expired.

Permissionless — anyone may call this once ledger.timestamp > unlock_at.

Errors

  • RecoveryNotPending — no recovery request is in progress.
  • RecoveryTimelockActive — the 7-day cooldown has not yet elapsed.
fn finalize_recovery(env: soroban_sdk::Env) -> Result<(), WalletError>

Cancel a pending recovery-key request.

Only the current wallet signer (the contract itself) may cancel. This lets a wallet owner who still holds their key abort a recovery attempt before it is finalized.

Errors

  • RecoveryNotPending — no recovery request is in progress.
fn cancel_recovery_request(env: soroban_sdk::Env) -> Result<(), WalletError>

Imports

WebAssembly Text (WAT) ▶