Abstract
This proposal extends the portable Keystore from EIP-8401 and the native account-abstraction transaction from EIP-8398 with three optional controls: policy-gated actors, delayed account locking, and nonce-free transactions. It assigns extension points reserved by those proposals while preserving the base transaction envelope and account address.
Motivation
EIP-8401 provides portable actors and account configuration. EIP-8398 uses that authority model for a native account-abstraction transaction with custom authentication, batching, sponsorship, and keyed sequential replay protection. Some deployments also need narrower session-key permissions, stronger protection against authority changes, and unordered transaction submission.
Those controls add storage, validation branches, and operational risk. Defining them as an extension keeps the Keystore and basic native transaction small while allowing chains and wallets to adopt the advanced behavior without a second transaction format.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
An implementation of this proposal MUST implement EIP-8401 and EIP-8398. Unless changed below, every base Keystore, validation, execution, gas-accounting, and RPC rule remains unchanged.
Scope Extensions
This proposal assigns one EIP-8398 scope bit:
| Bit | Value | Name | Authority |
|---|---|---|---|
| 1 | 0x02 | POLICY | May originate an AA transaction, with every call gated to the actor's policy manager |
The EIP-8398 meanings of SENDER, NONCE, SELF_PAYER, and SPONSOR_PAYER, and the EIP-8401 meaning of admin (scope == 0x00), remain unchanged.
For sender_auth, an actor is eligible when it is admin or carries SENDER or POLICY. Whenever POLICY is set, the policy gate applies even if SENDER is also set. EIP-8398's NONCE scope continues to govern sequential nonce channels.
Policy-Gated Actors
The Keystore adds two slots keyed by (account, actorId):
policy_manager(account, actorId) -> address
policy_commitment(account, actorId) -> bytes32It also adds account change type 5, SetActorPolicy, whose payload is:
abi.encode(bytes32 actorId, address manager, bytes32 commitment)SetActorPolicy MUST require an existing actor whose scope includes POLICY. It stores manager and commitment verbatim. Removing POLICY through AuthorizeActor, or applying RevokeActor, MUST clear both slots. An initial actor with POLICY starts with a zero manager and zero commitment because EIP-8401 initial actors contain no extension data.
For a transaction authenticated by a policy-bearing actor, the protocol snapshots policy_manager(sender, actorId) before call execution. Every call.to in every phase MUST equal that snapshot. A mismatched call is not dispatched and fails with:
error ActorPolicyViolation(bytes32 actorId, address target);This is an execution failure, not a transaction-validity failure. Existing EIP-8398 phase atomicity and nonce-consumption rules apply. The manager contract is responsible for interpreting policy_commitment and enforcing application-specific limits.
Account Locking
This proposal assigns account-state flag bits:
| Value | Name | Meaning |
|---|---|---|
0x04 | LOCKED | Actor configuration and delegation are frozen |
0x08 | UNLOCK_INITIATED | The lock delay is running |
The account state additionally stores a uint16 unlock_delay while no unlock is pending, or a uint48 unlocks_at while UNLOCK_INITIATED is set.
Two local account-change types are added:
| change_type | Name | Payload |
|---|---|---|
3 | Lock | abi.encode(uint16 unlockDelay) |
4 | Unlock | empty |
Lock and Unlock MUST use EIP-8401's Local channel, MUST be admin-authorized, and MUST each be the sole change in its signed batch.
Lock is valid only when the account is unlocked and unlockDelay != 0. It sets LOCKED, clears UNLOCK_INITIATED, and stores the delay. Unlock is valid only when LOCKED is set and no unlock is pending. It sets UNLOCK_INITIATED and stores unlocks_at = block.timestamp + unlock_delay.
While an account is effectively locked, actor authorization, actor revocation, policy changes, account import, and code delegation MUST be rejected through both the native transaction and EVM paths. Unlock and IncrementLocalEpoch remain permitted. Once block.timestamp >= unlocks_at, the lock is no longer effective and the next account operation MUST clear both lock flags and the lock time.
Implementations MUST emit:
event AccountLocked(address indexed account, uint16 unlockDelay);
event AccountUnlockInitiated(address indexed account, uint48 unlocksAt);Nonce-Free Transactions
EIP-8398 defines keyed sequential transaction nonces from 0 through NONCE_KEY_MAX - 1 and reserves NONCE_KEY_MAX. This proposal assigns that reserved value to the nonce-free mode.
Nonce authorization is:
| Actor | Permitted modes |
|---|---|
| Admin | Keyed sequential and nonce-free |
Restricted without NONCE | Nonce-free only |
Restricted with NONCE | Keyed sequential and nonce-free |
When nonce_key == NONCE_KEY_MAX, nonce_sequence MUST be zero and valid_before MUST be non-zero. No nonce slot is read or incremented.
The logical transaction identifier is:
REPLAY_ID_TYPE = 0x7901
replay_id = keccak256(REPLAY_ID_TYPE || rlp([
chain_id, resolved_sender, valid_after, valid_before,
account_changes, calls, metadata, payer
]))The protocol MUST reject a nonce-free transaction whose normalized valid_before is farther than NONCE_FREE_EXPIRY_WINDOW in the future. It MUST maintain a consensus-state replay set keyed by (sender, replay_id) until valid_before elapses. The replay set MUST use a fixed-capacity circular buffer of REPLAY_BUFFER_CAPACITY; if all entries are live and the buffer is full, the transaction is invalid.
Block builders MUST NOT include two transactions with the same (sender, replay_id). A pending nonce-free transaction with the same tuple is a replacement candidate under the node's normal fee-bump rules. Keyed transactions are replacement candidates when (sender, nonce_key, nonce_sequence) matches.
Validation and Execution Deltas
EIP-8398 processing changes as follows:
- Accept
POLICYas a sender initiation grant and apply the policy gate during call execution. - Reject configuration and delegation changes while the sender is effectively locked.
- When
nonce_key == NONCE_KEY_MAX, apply the nonce-free authorization and replay rules above instead of EIP-8398's sequential nonce check. - Skip nonce-sequence increment for
NONCE_KEY_MAX. - Charge for the nonce-free replay-set reads and writes instead of EIP-8398's sequential nonce storage operation.
Constants
| Name | Value | Meaning |
|---|---|---|
POLICY | 0x02 | Policy-gated actor scope |
LOCKED | 0x04 | Account-state lock flag |
UNLOCK_INITIATED | 0x08 | Account-state pending-unlock flag |
NONCE_KEY_MAX | 2^256 - 1 | Nonce-free transaction mode |
REPLAY_ID_TYPE | 0x7901 | Replay-identifier domain separator |
NONCE_FREE_EXPIRY_WINDOW | chain parameter | Maximum nonce-free validity window |
REPLAY_BUFFER_CAPACITY | chain parameter | Consensus replay-buffer capacity |
NONCE_FREE_EXPIRY_WINDOW and REPLAY_BUFFER_CAPACITY MUST be fixed under the chain's consensus rules. Capacity MUST be sufficient for the maximum accepted nonce-free throughput over the full expiry window.
Rationale
Why Keep the EIP-8398 Envelope?
The base transaction already contains the authentication, batching, sponsorship, validity, and nonce fields needed by these features. Assigning reserved values avoids a second transaction type and lets base transactions remain byte-compatible with extension-aware clients.
Why Separate Policies and Locking?
Policies introduce trusted manager contracts and additional execution gates. Locking introduces delayed state transitions and can temporarily prevent recovery. Both are useful controls, but neither is required for native account abstraction.
Why Separate Nonce-Free Transactions?
EIP-8398 keyed channels retain ordinary sequential replay protection. Nonce-free replay buffers remove sequence coordination entirely, but add consensus state, authorization rules, and mempool complexity that the base standard does not need.
Backwards Compatibility
An EIP-8398 transaction using any keyed sequential nonce and no actors using POLICY behaves unchanged. The EIP-8401 account representation and initial-actor commitment, transaction type, and signature payload remain unchanged.
Chains that implement only EIP-8401 and EIP-8398 continue to reject nonce_key == NONCE_KEY_MAX and treat POLICY as a non-authorizing reserved bit.
Security Considerations
Policy managers: A policy-bearing actor can reach only its configured manager, but that manager is trusted to enforce the commitment correctly. Accounts SHOULD use audited, non-upgradeable managers. Setting the account's own wallet code as manager is safe only if that code explicitly enforces the policy.
Policy lifecycle: Revocation and removal of POLICY MUST clear extension state so later reauthorization cannot resurrect stale permissions.
Account lock: A long delay can prevent legitimate recovery, while a short delay provides little protection. Wallets MUST present the delay clearly and retain an admin path capable of initiating unlock. IncrementLocalEpoch remains available while locked so outstanding local configuration signatures can be invalidated.
Nonce-free replay: The replay buffer and maximum validity window are consensus parameters. An undersized buffer can reject otherwise valid traffic; inconsistent parameters can cause consensus failure. The logical replay_id, rather than the full signed transaction hash, MUST key replay protection so re-signing or fee replacement cannot create a second includable transaction with identical effects.
Nonce-free authority: A restricted actor without NONCE may use nonce-free transactions but cannot consume an account's ordered transaction lanes. Implementations MUST apply this distinction after authentication.
Copyright
Copyright and related rights waived via CC0.
