Skip to content

feat(ua2): canonical sessions, hash binding, epochs, guardian events#6

Merged
hooftly merged 17 commits intomainfrom
develop
Oct 14, 2025
Merged

feat(ua2): canonical sessions, hash binding, epochs, guardian events#6
hooftly merged 17 commits intomainfrom
develop

Conversation

@hooftly
Copy link
Member

@hooftly hooftly commented Oct 14, 2025

Summary

This PR hardens UA²’s session + auth model and brings the SDK, hooks, and E2E flows into alignment. It introduces a canonical Session shape, stronger signature binding, epoch-based session invalidation on owner change, ERC-20 transferFrom gating with value caps, explicit auth-mode enforcement, and a sncast-backed E2E workflow. It also adds paymaster TX typings with a limit-aware demo adapter, normalizes SDK session types/usages, exposes a connect helper in hooks, and refreshes tests and docs.

Changes

  • Policy/Contracts
    • Canonical Session struct; enforce validAfter/validUntil and allowlist lengths
    • Bind chain/account/key/expiry/nonce into session-signing hash
    • Epoch-based invalidation (session_owner_epoch), retiring sessions on owner rotate/recovery
    • ERC-20 transferFrom gating + reusable value-cap helper and new errors
    • Auth: enforce single mode, gate recovery flows, allow cancel-recovery during guardian checks; add ERR_UNSUPPORTED_AUTH_MODE
  • SDK/Hooks
    • Realign session types; add resolved policy/counter + usage helper types
    • SessionsManager.use() helper; include calls_used in calldata; enforce call-count limits
    • useAccount exposes typed connect(ConnectOptions); align session calldata (id + pubkey) and drop unused max-value high felt
  • Paymasters
    • Add TX typings + PaymasterDeniedError
    • Implement limits-aware NoopPaymaster (call/calldata/fee ceilings) with sponsor metadata
  • E2E & Tests
    • Devnet: idempotent flow (deploy/reattach, cache addresses, full lifecycle with hashed keys + explicit success/revert assertions)
    • Sepolia: attach-only flow reusing shared helpers; Sepolia-friendly timings
    • Migrate tests to validAfter/validUntil; add normalization/serialization regression and lifecycle timing tests
    • Confirm unsponsored execution flagging when adapters return untouched TXs
  • Tooling/Docs
    • Shared utilities: project-root discovery, session key hashing, receipt logging
    • Check-in .env.sepolia template and allowlist through .gitignore for demos
    • Update deploy docs and runbooks to reference new flows and templates

Motivation

  • Eliminate replay/zombie session risks and clarify policy semantics
  • Standardize adapter surfaces (paymasters) and improve DX for integrators
  • Make E2E runs reliable/repeatable across devnet and Sepolia
  • Keep SDK, hooks, and contracts in tight lockstep to reduce integration bugs

Testing

  • Unit/integration:
    • Session expiry/denials/value caps; normalization/serialization; lifecycle with injected clock
    • Epoch bump regression (owner change retires sessions)
    • Paymaster decoration success, limit violations, default fee injection
    • Hooks/SDK calldata layout and SessionsManager.use() behavior
  • E2E:
    • Devnet idempotent run (deploy or reattach) with hashed session keys
    • Sepolia attach-only validations, expected policy reverts, post-revoke denials

Checklist

  • Tests
  • Docs
  • Lint
  • Ready for review

hooftly and others added 17 commits October 13, 2025 20:13
- Add canonical Session struct (session key, valid_after/until, value cap,
  allowlist lengths) and export for contract consumers
- Update UA2 account to use the struct; enforce declared vs actual
  allowlist lengths; require valid_after < valid_until; emit expanded
  session metadata in events
- Refresh tests to exercise length mismatches and activation window logic
- Update docs and SDK helpers to reflect the revised policy shape
- Extend session message hashing to bind chain, account, session key,
  call digest, expiry, and nonce to tighten replay protection
- Update signing helpers and session-focused tests to use the new
  message shape while continuing to assert nonce replay prevention
- Document the bound message fields in the validation guide
- Replace per-guardian boolean map with _record_recovery_confirmation()
- Count each guardian exactly once per proposal using existing proposal id
- Preserve and reuse current recovery events and proposal tracking
- Update architecture and RFC docs to match simplified storage layout
- Centralize reusable error identifiers in a new errors module; replace
  inline definitions within the account contract for consistent messaging
- Add GuardianProposed and GuardianFinalized events to the account ABI
  and emit them during recovery proposal and execution alongside owner
  rotation logic
- Update contract tests to assert new guardian events, verify recovery
  cancellation signaling, and import shared error constants
- Improve consistency and observability across the recovery lifecycle
- Introduce session_owner_epoch counter and owner_epoch in session
  policies; bump epoch on owner rotation or recovery to retire existing
  sessions automatically
- Enforce stale-session detection with ERR_SESSION_STALE in both
  validation and nonce accounting to block zombie usage
- Update session tests, including a rotation regression, to cover epoch
  semantics and ensure old sessions cannot execute after owner change
- Add session testing utilities and focused cases for expiry, selector
  denials, target denials, and per-call value caps to surface failures
- Extend guardian recovery coverage with explicit timelock, finalize,
  and cancel flows plus associated event assertions
- Rename owner rotation regression test to
  test_rotate_owner_revokes_sessions for clarity and suite alignment
- Add transferFrom support and a reusable value-cap helper so sessions
  gate ERC-20 spends; assert session creation invariants via new error
  constants
- Expand mock ERC-20 and session tests to cover transferFrom flows,
  empty allowlists, not-ready windows, and cross-session signature
  reuse failures
- Document allowlist defaults, recommended limits, additional error
  identifiers, and clarify native value transfers are out of scope for
  v0 value caps
- Add ERR_UNSUPPORTED_AUTH_MODE
- Expand UA2 account validation to gate recovery flows, ensure single
  auth-mode selection, and permit cancel-recovery selectors during
  guardian checks
- Introduce __validate__ helpers: recovery-only call detection and
  nonce-safe mode counting; return OZ validation for owner paths after
  session/guardian enforcement
- Replace devnet E2E runner with a sncast-backed workflow
- Align policy typing across scripts and app to validAfter/validUntil
  semantics in automation and UI
- Update core session tests to construct policies with validAfter/validUntil
  and verify guard output against the new fields (replacing expiresAt)
- Adjust React hooks test helper to create sessions using the updated
  policy shape
- Make devnet E2E idempotent: auto-deploy or reattach UA2, cache
  addresses, and run full session lifecycle with hashed keys and
  explicit success/revert assertions
- Rework Sepolia E2E into attach-only flow; reuse shared helpers to
  validate successful usage, expected policy reverts, and post-revoke
  denials with Sepolia-friendly timings
- Expose shared utilities for project-root discovery, session key
  hashing, and receipt logging
- Add checked-in .env.sepolia template and allow it through .gitignore
  for demos
- Improve reliability, repeatability, and parity across local and Sepolia
  E2E paths
- Add resolved policy/counter shapes and explicit usage helper types to
  match on-chain Session struct
- Enhance SessionsManager to normalize policies, expose a `use` helper,
  include `calls_used` in calldata serialization, and enforce call-count
  limits while keeping guard-builder defaults in sync
- Re-export new session types publicly
- Update tests to cover refined calldata layout and SessionsManager.use
  behavior
- Add connect helper to useAccount hook typed with ConnectOptions so
  consumers can initiate connections directly from the hook
- Update session creation to include both session id and pubkey in the
  calldata sent over the transport, keeping key slots aligned
- Simplify calldata builder by dropping the unused max-value high felt
- Adjust unit test to assert the revised calldata layout
- Add explicit paymaster transaction typings and PaymasterDeniedError to
  standardize adapter interfaces
- Implement limits-aware NoopPaymaster enforcing call, calldata, and fee
  ceilings while attaching sponsor metadata
- Expand unit tests to cover successful decoration, limit violations,
  and default fee injection for the demo adapter
…ter flag

- Add regression test to verify policies normalize invalid input and emit
  expected felt calldata during serialization
- Add lifecycle test for activation and expiry using injected clock and
  missing-session scenarios
- Confirm paymaster runners mark executions as unsponsored when adapters
  return untouched transactions with no metadata
@hooftly hooftly merged commit 48891e0 into main Oct 14, 2025
3 checks passed
@hooftly hooftly deleted the develop branch October 14, 2025 16:10
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.

1 participant