Back to Research
7 min read0%
Post-QuantumMay 21, 2026

NiceTry: A Frame Transaction-ready Post Quantum Wallet

By Alessandro Baiocchi

AI agent? Read this article as clean Markdown to save tokens.
NiceTry: A Frame Transaction-ready Post Quantum Wallet

NiceTry: A Frame Transaction-ready Post Quantum Wallet

Introduction

When looking at Ethereum and other EVM chains, it seems clear that post-quantum security runs through account abstraction. Most teams working on these problems have converged on this, and as more concrete proposals appear, no other path looks viable.

As we build our post-quantum Ethereum wallet infra 'NiceTry', which is the reference implementation of our Ephemeral Keys Protocol, we started experimenting with what could be the future of account abstraction: frame transactions.

In this article we cover how NiceTry works under frame transactions, and how the implementation differs from the canonical ERC-4337 version.

What is NiceTry

NiceTry is a wallet infrastructure project that acts as the reference implementation of our ephemeral-key post-quantum protocol.

Following the core design, the user's account address stays stable, while the signing key changes over time. Each transaction is authorized by a short-lived key, and successful validation must force the account to move to the next key. The current NiceTry implementation uses FORS+C, a hash-based signature, as the primary signature scheme.

In the ERC-4337 version, NiceTry is implemented as a smart account whose validateUserOp checks a FORS signature and rotates the account owner during validation. With frame transactions this logic changes, and instead of UserOperation, EntryPoint, and validateUserOp, the account expresses its validation logic inside the frame transaction model.

The NiceTry frame account design keeps the same security goal, but implements it differently to match the frame transaction's standard: validation checks the FORS signature, then requires the very next frame to rotate the signer.

What are Frame Transactions

EIP-8141 introduces a new transaction type built from a sequence of frames. Instead of one transaction containing one top-level call, a frame transaction contains multiple framed calls, each with its own mode, target, gas limit, value, and calldata.

Conceptually, a frame transaction looks like this:

tx = {
  sender,
  nonce,
  frames: [
    [mode, flags, target, gas_limit, value, data],
    ...
  ],
  fee fields
}

The modes relevant to NiceTry are:

VERIFY   validate the transaction
SENDER   execute as the transaction sender
DEFAULT  execute through the frame transaction entry context

The important change is that account validation becomes native. A smart account can define its own validation logic in a VERIFY frame, instead of relying on an ECDSA signature over a normal transaction or on ERC-4337's validateUserOp.

This is the key difference for NiceTry: the VERIFY frame can approve execution, but it cannot directly rotate the signer because the VERIFY frame itself is bound to be static: it can execute any code that is necessary to verify the signature and read all necessary storage, but cannot change the state in doing so. Rotation has to modify the state by updating the contract's owner, therefore has to happen in a later execution frame, and validation must ensure that this later frame exists.

ERC-4337 Account vs Frame Account

The ERC-4337 account and the frame account enforce the same high-level rule, but the execution model is different.

AreaERC-4337 NiceTry AccountFrame NiceTry Account
Transaction objectUserOperationNative frame transaction
Validation entry pointvalidateUserOp called by EntryPointVERIFY frame
Execution entry pointAccount execute / calldata from the UserOperationLater SENDER frames
Signature checked againstuserOpHashFrame transaction signature hash
Rotation timingCan happen during account validationCannot happen in VERIFY; must happen in a later frame
Approval mechanismReturn value / EntryPoint validation semanticsAPPROVE instruction
User execution dependencyEntryPoint executes after validationSENDER frames execute only after approval
Frame inspectionNot applicableAccount can inspect the next frame before approval

In ERC-4337, signer rotation can be part of validateUserOp. Validation happens before user execution, so if user execution later fails, the signer has still rotated.

In frame transactions aVERIFY frame is static, so the account cannot update owner during validation. If NiceTry only checked a FORS signature and called APPROVE, it would approve execution without forcing rotation, breaking the ephemeral-key invariant.

The frame account therefore uses a different pattern:

Frame 0: VERIFY     -     check FORS signature and require Frame 1 to be rotation
Frame 1: SENDER     -     call rotateOwner(nextOwner)
Frame 2+: SENDER    -     user actions

Rotation Invariant

The security invariant is:

No frame transaction should be approved unless signer rotation is already scheduled as the next frame.

NiceTry enforces that invariant inside the frame account validation path.

During the VERIFY frame, the account first checks the FORS signature against the current owner. If the signature is invalid, validation fails.

If the signature is valid, the account does not immediately approve the transaction. It inspects the next frame and requires it to be the rotation frame.

The next frame must satisfy all of these checks:

mode      == SENDER
target    == address(this)
value     == 0
atomic    == false
selector  == rotateOwner(address)
nextOwner != address(0)

In plain English: the frame immediately after validation must be a self-call from the account to rotateOwner(address), with no ETH transfer, no atomic batching, and a nonzero replacement owner.

Only after those checks pass does validation approve execution and payment.

The resulting flow is:

1. VERIFY frame runs on the NiceTry frame account.
2. Account verifies the FORS signature.
3. Account inspects frame N + 1.
4. Account confirms frame N + 1 is exactly rotateOwner(nextOwner).
5. Account approves execution/payment.
6. The next SENDER frame rotates the owner.
7. User execution frames run after rotation.

The interaction looks like this:

Rendering diagramma…

This interaction flow preserves the important property from the ERC-4337 design: even if later user execution fails, the signer rotation has already happened. The used FORS key is not left as the account's active key for a future transaction.

Therefore, the frame account is not relying on wallet discipline or off-chain convention, and it is not saying "clients should include a rotation frame." What it does is making rotation a validation requirement, and if the transaction does not put rotation immediately after verification, the account refuses to approve the transaction.

One small side effect of this change of paradigm is that, as of the current EIP-8141 spec state, this kind of account cannot be used as a paymaster, as it would not be able to add the rotation frame for itself to the user’s transaction.

Conclusions

Frame transactions do not remove the need for smart account logic, instead, they move the account validation surface closer to the protocol. For NiceTry, that is exactly the interesting part: the same ephemeral-key invariant can be expressed without relying on ERC-4337's EntryPoint flow.

The main difference is that signer rotation cannot happen inside the VERIFY frame itself, because VERIFY execution is bound to be static. The account has to split validation and rotation into two phases: first prove that the transaction is authorized, then require that the next executable frame performs the rotation.

The resulting model is simple:

VERIFY -> mandatory rotateOwner(nextOwner) -> user execution

We believe that native account abstraction is a step forward for Ethereum, eliminating the need for a heavy infrastructure surrounding current account abstraction. The current state of the EIP-8141 proposal brings some restrictions to the possibilities of the validation flow, which as we've shown in this article require a different account paradigm to keep invariants intact.