Back to specialisms

Smart Accounts & Wallets: how we design permissions users can control

Dmitry Sergeev·12 min read
Tags:
  • Smart accounts
  • ERC-4337
  • Session keys
  • Paymasters
  • Recovery
  • Permissions

The user problem

A user signs in, selects an action and then encounters another wallet prompt. The next step needs a native gas token they do not hold. An automated strategy stops when its session expires, while recovering a lost device may require a process the user never configured. These interruptions turn account management into part of every product interaction.

Removing prompts changes the security model. An application that acts without asking each time needs a standing permission, and that permission remains useful to an attacker if the application or its session key is compromised. Gas sponsorship introduces a separate budget that can be exhausted. Recovery introduces another route to account control.

We design these capabilities together. The owner approves a defined scope, the account enforces it, and the application explains what remains possible when a key or service fails. Fewer signatures should come from decisions the user has already authorised, with limits they can inspect and revoke.

What we build

We build smart accounts and the infrastructure around their use: account creation, application permissions, operation submission, sponsorship and recovery. The scope depends on who controls the account, which actions the product needs and how users regain access after losing a device.

ComponentWhat it handles
Smart accountsOwnership, signature validation, account deployment, controlled execution and supported module installation.
Session keysTemporary application access with restrictions on contracts, methods, recipients, amounts and validity.
Delegated executionBots, relayers or application workers acting within an approved policy, including validation of every call in a batch.
Gas sponsorshipEligibility checks, sponsorship authorisations, spending budgets, deposit monitoring and an explicit alternative when sponsorship stops.
RecoveryThe agreed process for replacing owner credentials, cancelling unauthorised recovery and invalidating affected sessions.
SDK and backendPermission encoding, readable approval summaries, operation construction, provider routing, receipt tracking and operational monitoring.

The custody model is an early decision. We identify where owner and session credentials are created, stored and used, including any embedded-wallet provider. Passkeys can simplify authentication, but the architecture still has to specify how that authentication authorises an account operation and what happens when the original device is unavailable.

How we design permissions

Every permission answers the same questions: who → may do what → for how long → within which limit → how access is revoked. We work through actual product actions before choosing validators or writing a general permission API.

Start with actions the application needs

For a game, the list might include crafting, equipping and claiming rewards. A trading integration needs more detail: permitted assets, routers, output recipient and price constraints. We separate routine actions from changing the owner, installing modules, upgrading the account or granting further permissions.

Those administrative actions remain outside ordinary session authority. Otherwise a narrowly described session could install a broader validator or extend its own expiry. The implementation review includes indirect routes to those actions, such as self-calls and nested execution.

Turn each action into an enforceable rule

A contract allowlist is only a starting point. The same router method may accept any recipient or token. We define which arguments need checking and implement bounded decoders for the supported integrations. Unsupported call shapes are rejected rather than treated as harmless because their target address is approved.

The owner signs the canonical permission object used by the account. The SDK generates the approval summary from that same object, including amounts, destinations and expiry. This avoids a screen that describes a small allowance while the encoded policy grants something broader.

An illustrative game permission could look like this:

QuestionApproved boundary
Who?One session public key associated with the current game session.
What?Specified craft and equip methods on two approved contracts; crafted items must go to the user's account.
How long?One hour, with expiry checked against chain time.
How much?No native-token transfer and at most 20 game tokens across the session.
What stays excluded?General transfers, token approvals, account upgrades and permission changes.
How is access removed?An owner-authorised on-chain revocation, with pending and confirmed states shown separately.

The amounts and duration are example inputs. For a real integration, we check that the target contracts expose enough information to enforce the proposed rule. A product promise that cannot be verified from the supported execution path needs a narrower scope or a different integration.

Define what the spending limit measures

“Up to 100 tokens” could mean per call, per session or per day. We specify the asset, units, period, reset rule and whether fees consume the same budget. Multiple sessions also need an explicit relationship: independent allowances can add up to much more authority than the owner intended.

Security-critical cumulative limits belong on-chain. The implementation must handle concurrent operations and the ordering of validation and execution, so two requests cannot both rely on the same unused budget. We define whether failed calls consume a limit and test that behaviour through the complete account execution path.

Indirect spending needs its own analysis. A deposit, swap or approval can create an economic effect that a direct-transfer counter misses. We use narrow protocol-specific policies where the product requires them; unrestricted calls into arbitrary DeFi contracts cannot inherit a credible universal spending guarantee.

Make revocation part of the first integration

Removing a key from a device or marking a session inactive in the backend does not revoke its on-chain authority. The owner needs a supported submission path for revocation and a way to verify the resulting account state. We define both individual revocation and, where required, invalidation of all previous sessions through an account-level generation counter.

The first complete implementation includes account creation, session approval, a permitted action, a rejected action and revocation. We then exercise expiry, concurrent use and provider failure before extending the policy surface. This validates the permission model while the integration is still small enough to change.

Decisions that matter

Can the session leave authority behind after it expires?

An expired session key can no longer authorise new account actions under its policy, but an allowance it previously granted to another contract can remain usable. Signed spending permissions may also have their own expiry and revocation rules. We inventory these effects separately from the session record.

The default integration can forbid approval methods or permit only named spenders and bounded amounts. Some flows can grant an exact allowance and reset it within the same atomic operation. Where standing allowances are necessary, their visibility and revocation belong in the product, including what the user must do after a suspected compromise.

Does a batch preserve the same limits?

Combining approval, swap and deposit into one action reduces prompts, but every nested call still needs validation. The account checks individual permissions and aggregate spending. It also defines whether a failure reverts the whole batch or leaves earlier actions completed, because the interface and accounting must reflect that choice.

Session access to unrestricted delegatecall is excluded from our default design: code running in the account's storage context could alter the permission system itself. Re-entry and self-calls need explicit controls too. A batch interface must not become a second route to owner-only functions.

What can a compromised session key still do?

A stolen session key can perform the actions that remain valid within its scope. Expiry, recipient restrictions and cumulative limits bound that exposure; they do not make the compromise harmless. We keep sessions short enough for the use case and separate them by application or automation task where isolation is useful.

Revocation takes effect through chain execution. An attacker's operation may execute before the owner's revocation, and that completed action is not undone. We test revocation ordering, including operations validated earlier in a bundle, and place current-state checks at the points required to enforce the chosen semantics. Where supported, a separate owner nonce lane keeps revocation from waiting behind a stuck session queue, although network inclusion remains an external dependency.

Who is allowed to recover the account?

Losing a session key and losing the owner credential are different incidents. An available owner can revoke and replace a session. Loss of the owner credential needs a recovery mechanism configured in advance, such as an additional credential or an approved guardian threshold. We specify who may initiate recovery, the evidence or approvals required, any waiting period and who may cancel it.

Recovery can become a takeover path, so its scope must be visible. A support agent who verifies an email address should not silently acquire unrestricted signing authority. For a delayed guardian flow, the design also states which actions remain available during the delay and how the legitimate owner is notified of an unexpected request.

Completion must address existing authority. We define which owner credential is replaced, which sessions and pre-signed requests become invalid, and which external token allowances need separate action. If the user loses every configured recovery factor, the product must state that limit instead of implying support can always restore access.

What happens when the bundler or paymaster stops working?

The account determines whether an action is authorised; the paymaster determines whether it will fund the gas. A sponsorship refusal must not widen session permissions or silently charge the user. We distinguish budget exhaustion, unavailable service and policy rejection so the application can present the appropriate next step.

A fallback route must be compatible with the account, network and selected execution configuration. Before resubmission, the SDK checks the existing operation and nonce state. Switching providers may require a new sponsorship authorisation or signature if operation fields change. We preserve the approved action and expose any changed cost for consent.

Self-funded execution is useful only when the account supports it and the user has the required funds. We verify that path rather than presenting it as a universal escape hatch. If neither sponsorship nor a supported funded route is available, the interface preserves the action as pending or failed with a clear reason.

How is sponsorship guarded from valid but wasteful use?

An operation can be permitted by the account while providing no useful outcome for the sponsor. The sponsorship service therefore has its own eligible methods, per-user and application budgets, rate limits and maximum gas costs. Concurrent requests reserve budget before submission, with actual costs reconciled afterward.

Monitoring covers deposit levels, rejected requests, failed execution costs and unusual consumption by one application. Sponsorship keys remain separate from user credentials and treasury authority. If the product charges gas in a token, the user approves a maximum charge and quote validity; a higher network cost cannot silently increase that charge.

Can an upgrade change permissions already approved?

Validators and recovery modules are trusted account code. We document who can install or replace them and how those changes affect existing sessions. A policy that references an upgradeable application also needs review when that application's behaviour changes, even if its address and method names remain the same.

The deployment package pins account, factory and module versions and records their administrative powers. Migration testing checks existing accounts, active sessions, pending operations and recovery requests. A working new-account demonstration alone does not establish that a release is compatible with users already holding assets.

Selected work

KeyForgeCore provides the account and permission example. VeloPass Labs applies embedded accounts to a consumer journey, while MEV Auction addresses the submission path for account-abstraction operations. The scope below reflects the architecture documented in the project materials.

Key Forge: temporary access with account-enforced limits

The Key Forge project addresses repeated wallet prompts in games and automated applications. Its central problem is giving an application enough authority to act between prompts without letting that authority expand into account ownership.

We separated owner validation from session validation and defined policies for target contracts, methods, amounts, expiry and revocation. Batch inspection covers every call and aggregate limits. Approval policies address allowances that could survive session expiry, while owner-only administration remains outside ordinary session access.

The architecture includes smart accounts, a session validator, specialised policy modules, a TypeScript policy compiler and SDK, sponsorship services and compatible provider routing. On-chain revocation state and spending counters preserve enforcement when the backend is unavailable. Separate nonce lanes and session generations support owner intervention without relying on an application's local session store. Read the Key Forge case study.

VeloPass Labs: embedded accounts beyond support's control

VeloPass Labs brings wallet functionality into ticket purchasing and resale. Fans need ordinary sign-in and recovery behaviour, while the platform must preserve ticket ownership, purchase limits and the validity of venue credentials when devices or holders change.

We built the sign-in around passkeys and embedded smart accounts, with sponsorship governed by the event and operation configuration. A pseudonymous Fan ID remains separate from wallet addresses so changing devices does not automatically reset purchase eligibility. Short-lived purchase authorisations bind the event, product, quantity, policy version and nonce.

The account integration connects to controlled ticket transfers and a separate admission-credential service. Recovery can replace authentication or a lost presentation credential without giving ordinary support staff unilateral power to move arbitrary tickets. Ownership changes also require revoking the previous holder's entry credential, with explicit limits when venue systems are disconnected. Read the VeloPass Labs case study.

MEV Auction: submission policy that holds after signing

MEV Auction handles private transaction routing, including account-abstraction operations. A UserOperation carries sensitive intent inside account calldata, so examining only its outer execution envelope would miss the information that the routing policy needs to protect.

The architecture places a private bundler before the auction pipeline and decodes the inner target and method for controlled disclosure. Inner arguments, signatures and paymaster context stay out of searcher-facing hints. Routing authority remains separate from the client's keys and permission to authorise a changed transaction.

The scope includes private ingestion, simulation, disclosure controls, routing and receipt reconciliation. Strict-private orders expire if the approved route cannot include them; public fallback requires a policy that permits it. This is a submission integration, with the user's account ownership and signing authority remaining outside the routing service. Read the MEV Auction case study.

What the client receives

The delivery package connects account contracts to the application and the team that will operate its infrastructure. Acceptance covers both permitted actions and attempts to exceed authority, including after expiry, revocation, recovery or a service outage.

  • Account contracts, factory and selected validators or recovery modules, with documented ownership, upgrade powers and supported execution paths.
  • A permission engine and SDK that encode policies, display the same scope for approval, construct operations and distinguish policy rejection from infrastructure or target-call failures.
  • Backend infrastructure for sponsorship decisions, budget reservations, session metadata, receipt indexing and operational alerts, with critical authority enforced by the account.
  • Tested integrations for the selected authentication provider, applications, bundlers, paymasters and networks, including supported fallback and self-funded paths.
  • Production configuration covering deployed versions and addresses, signing access, sponsor funding, provider health, cost monitoring and incident procedures.
  • Documentation and validation evidence for permission limits, concurrency, batch execution, compromised sessions, recovery and release compatibility, including the results of agreed security review work.

Before launch, we run the complete recovery and revocation journeys with the product team, including a user who has lost the usual device and a sponsor that has stopped paying. The team must be able to explain what authority remains, who can change it and how the user can act through the available infrastructure.

See our architecture in practice.

DEVLAB · ARCHITECTURE EXAMPLE

Agent
Commerce

A look inside the software architecture behind Agent Commerce.

View architecture
Agent Commerce — Software Architecture, designed by Dmitry Sergeev

START A PROJECT

Ready to move the
project forward?

Tell us what you are building and what you
need help with. Start with a call or send the
details in writing.

START WITH THE CONTEXT

Send a project brief

Describe the project in your own words or attach an existing
brief, architecture document, or requirements file.

NO PITCH DECK NEEDED

Schedule a call

Book a focused 30-minute conversation about the product,
architecture, scope, or delivery plan.

START WITH THE CONTEXT

Send a project brief

Describe the project in your own words or attach an existing
brief, architecture document, or requirements file.

What do you need?

Prefer your own email? Write to [email protected]