Skip to content

Add smart account support for OpenZeppelin contracts#208

Merged
christian-rogobete merged 57 commits into
masterfrom
feature/oz-smart-account
Jun 8, 2026
Merged

Add smart account support for OpenZeppelin contracts#208
christian-rogobete merged 57 commits into
masterfrom
feature/oz-smart-account

Conversation

@christian-rogobete
Copy link
Copy Markdown
Member

@christian-rogobete christian-rogobete commented Jun 5, 2026

Description

Add passkey-based smart account support to the iOS/macOS Stellar SDK, targeting OpenZeppelin stellar-contracts v0.7.1.

SDK

Two-layer architecture under stellarsdk/stellarsdk/smartaccount/.

Core layer (contract-agnostic):

  • WebAuthnProvider protocol and AppleWebAuthnProvider, an AuthenticationServices-backed implementation providing passkey registration and assertion for iOS 16+ and macOS 13+
  • WebAuthn public key extraction from COSE keys with on-curve validation
  • DER signature normalization with low-S enforcement
  • Deterministic contract address derivation from credential ID
  • Typed error hierarchy (SmartAccountException) with families for configuration, wallet, credential, WebAuthn, transaction, signer, validation, storage, session, and indexer errors

OZ layer (OpenZeppelin-specific):

  • OZSmartAccountKit: wallet creation (passkey registration + contract deployment), wallet connection (session restore + fresh authentication), token transfers, and arbitrary Soroban invocations
  • Context rule management (create, update name/expiry, remove)
  • Signer management (add/remove passkey, Ed25519, and delegated signers)
  • Policy enforcement (simple threshold, weighted threshold, spending limit)
  • Multi-signer transfer workflows with signer selection
  • Relayer client (host function and signed-XDR submission modes)
  • Indexer client (credential-to-contract lookup)
  • Credential management with deployment-status tracking
  • Lifecycle event system
  • External wallet adapter interface for delegated signing
  • Storage adapters: Keychain (encrypted, production), UserDefaults (scoped), and in-memory (tests)

SDK core additions (outside the smartaccount package, additive only):

  • Data extensions: base64url encode/decode and constant-time comparison
  • SorobanServer: transaction polling and resource cleanup
  • StellarProtocolConstants: stroop and ledger conversion constants

Documentation

Under docs/smart-accounts/:

  • Onboarding guide covering smart account concepts
  • Usage guide with configuration and code examples
  • API reference (signer types, error hierarchy, kit operations, context rules, policies, storage)
  • Per-platform WebAuthn setup guides (iOS, macOS)

An agent skill under skills/stellar-ios-mac-sdk/ with curated references and a generated API signature index.

Tests

Unit tests covering COSE public key extraction, signer and signature encoding, contract address derivation, DER signature normalization, auth payload construction, policy SCVal encoding, storage adapters, credential management, the event system, error mapping, and exception factories.

Adds the protocol-agnostic smart-account package: signer types
(delegated and external WebAuthn / Ed25519), the sealed
exception hierarchy, and public-key size constants. Adds the
OpenZeppelin contract identification constants used by future
OpenZeppelin-specific layers.

Also adds a public pollTransaction helper on SorobanServer for
polling RPC transaction results.
Adds the platform-agnostic WebAuthn provider abstraction
along with the registration and authentication result types
and the AllowCredential type for restricting credential
discovery during authentication.
Adds the OpenZeppelin Smart Account integration in
smartaccount/oz/ (signer types, signature wrappers, auth payload
codec, auth-digest builder, and signer and policy builders) and
the supporting WebAuthn cryptographic primitives in
smartaccount/core/ (DER signature parser with low-S
normalization, COSE-to-SEC1 public key extractor, secp256r1
on-curve validation, and credential-derived contract address
derivation). Adds Data extensions for base64url encoding and
constant-time byte comparison, an SCValXDR.i128 factory for
stroop amounts, a String overload for Operation.toXDRAmount, and
ledger and stroop constants on StellarProtocolConstants.
Adds six golden-vector tests asserting byte-level output of
buildAuthDigest, the OZ AuthPayload codec, and OZWebAuthnSignature
ScVal serialization for a canonical fixture set. The hex outputs
are pinned to specific values across the four buildAuthDigest
fixtures (empty, single, unsorted, and long signaturePayload
boundary) plus one AuthPayload and one WebAuthnSignature wire-shape
fixture, providing a byte-identical reference for cross-SDK
verification.
Adds OZSmartAccountConfig with a chainable builder, input
validation on required fields, and a deterministic default
deployer derivation. Adds a StorageAdapter protocol with an
actor-isolated InMemoryStorageAdapter, the credential and
session data structures used by every adapter implementation,
and the ExternalWalletAdapter protocol for delegating signing to
external wallet bridges. Adds internal JSON serialization
helpers that persistent adapters will reuse to round-trip
credentials and sessions through encoded form.
Adds SmartAccountEvent (sealed event hierarchy),
SmartAccountEventEmitter (typed and untyped subscribe / unsubscribe,
isolated error handler, snapshot-then-dispatch under a serial lock),
internal validation helpers for contract addresses, Stellar accounts
and localhost URLs, and the OZ context-rule builders including the
sealed ContextRuleType and ParsedContextRule data classes that the
context-rule manager will consume.
Adds OZIndexerClient (credential / address / contract / stats / health
lookups) and OZRelayerClient (sponsored transaction submission) on
URLSession, with HTTPS-only allowlist, no-redirect delegate, and
response body-size caps. Centralises the default-indexer-URL lookup
behind OZIndexerClient.getDefaultUrl.
Adds OZTransactionOperations (transfer, contractCall, executeAndSubmit,
submit, fundWallet) and OZWalletOperations (createWallet, connectWallet,
authenticatePasskey, deployPendingCredential), with simulate / sign /
re-simulate / submit pipeline, deterministic deployer keypair flow,
HTTPS-only allowlist preserved, and config bounds on signature
expiration and timeout. Backed by a forward-reference protocol the
smart-account kit will conform to.
Adds OZSignerManager, OZPolicyManager, OZContextRuleManager,
OZCredentialManager, OZMultiSignerManager, and OZExternalSignerManager
covering signer/policy/context-rule/credential CRUD over the
smart-account contract surface, multi-signer auth-entry pipeline, and
Ed25519/external-wallet signer routing. Backed by additive extensions
to the Phase 6 forward-reference protocols and a shared submission
router.
Splits OZContextRuleManager parsing into a dedicated extension,
tightens External-signer verifier parsing to contract-only, gates
keypair signing on private-seed availability, renames the connected-
wallet storage key for namespace clarity, and adds cancellation,
read-side, amountToStroops, and cloneAuthEntry tests. Switches the
Phase 7 test placeholder URL to the immediate-fail loopback.
Adds OZSmartAccountKit, the top-level class that composes the OZ
smart-account managers and exposes them along with the event
emitter, indexer client, and relayer client. Gives SorobanServer
an owned URLSession with an idempotent close() so the kit can
release the shared RPC transport.
Adds AppleWebAuthnProvider (ASAuthorization-based, iOS 16+/macOS 13+),
KeychainStorageAdapter, and UserDefaultsStorageAdapter conforming to
the existing storage protocol. Introduces SecItemShim, a small
indirection that makes Keychain failure modes injectable from tests.
Replaces the placeholder XCTSkip tests with real assertions that
exercise OZSmartAccountKit's session lifecycle through the public
factory, covering disconnect side effects, session/credential
storage orthogonality, and the requireConnected throw paths.
Adds optional maxScanId parameters to OZContextRuleManager's
getAllContextRules and listContextRules so callers can override
the configured scan cap on a per-call basis without reconfiguring
the kit. Adds a new SmartAccountEventCredentialSyncFailed event
emitted when OZCredentialManager.sync cannot reach the RPC,
giving consumers a signal to react to sync failures alongside
the existing boolean return.
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Jun 5, 2026

Codecov Report

❌ Patch coverage is 95.06195% with 279 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.13%. Comparing base (0750730) to head (4fee074).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
...rsdk/smartaccount/core/AppleWebAuthnProvider.swift 74.39% 63 Missing ⚠️
...llarsdk/smartaccount/oz/OZMultiSignerManager.swift 91.71% 55 Missing ⚠️
...ellarsdk/smartaccount/core/SmartAccountUtils.swift 94.17% 25 Missing ⚠️
...k/stellarsdk/smartaccount/oz/OZRelayerClient.swift 90.24% 24 Missing ⚠️
...tellarsdk/smartaccount/oz/OZSmartAccountAuth.swift 86.30% 20 Missing ⚠️
...sdk/smartaccount/oz/OZKeychainStorageAdapter.swift 94.11% 14 Missing ⚠️
...k/stellarsdk/smartaccount/oz/OZPolicyManager.swift 95.65% 14 Missing ⚠️
...k/stellarsdk/smartaccount/oz/OZIndexerClient.swift 97.21% 9 Missing ⚠️
...sdk/stellarsdk/smartaccount/oz/OZSecItemShim.swift 0.00% 9 Missing ⚠️
...sdk/smartaccount/oz/OZSmartAccountSignatures.swift 88.23% 8 Missing ⚠️
... and 12 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #208      +/-   ##
==========================================
+ Coverage   90.89%   91.13%   +0.24%     
==========================================
  Files         754      793      +39     
  Lines       23914    31942    +8028     
==========================================
+ Hits        21736    29111    +7375     
- Misses       2178     2831     +653     
Flag Coverage Δ
unit 91.13% <95.06%> (+0.24%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...rsdk/stellarsdk/extensions/Data+ConstantTime.swift 100.00% <100.00%> (ø)
stellarsdk/stellarsdk/sdk/Operation.swift 94.68% <100.00%> (+0.36%) ⬆️
...dk/smartaccount/core/WebAuthnAllowCredential.swift 100.00% <100.00%> (ø)
...tellarsdk/smartaccount/core/WebAuthnProvider.swift 100.00% <100.00%> (ø)
...llarsdk/smartaccount/oz/OZContextRuleManager.swift 100.00% <100.00%> (ø)
.../stellarsdk/smartaccount/oz/OZManagerHelpers.swift 100.00% <100.00%> (ø)
...k/stellarsdk/smartaccount/oz/OZSignerManager.swift 100.00% <100.00%> (ø)
...arsdk/smartaccount/oz/OZSmartAccountBuilders.swift 100.00% <100.00%> (ø)
...sdk/smartaccount/oz/OZSmartAccountKit+Wiring.swift 100.00% <100.00%> (ø)
...stellarsdk/smartaccount/oz/OZSmartAccountKit.swift 100.00% <100.00%> (ø)
... and 32 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@christian-rogobete christian-rogobete merged commit f81cd93 into master Jun 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants