Account Abstraction Recovery Interface
Abstract
Introduce a universal account abstraction recovery mechanism recoverAccess(subject, provider, proof)
along with recovery provider management functions for smart accounts to securely update their access subject.
Motivation
Account abstraction and the “contractization” of EOAs are important Ethereum milestones for improving on-chain UX and off-chain security. A wide range of smart accounts emerge daily, aiming to simplify the steep onboarding curve for new users. The ultimate smart account experience is to never ask them to deal with private keys, yet still allow for full account control and access recovery. With the developments in the Zero-Knowledge Artificial Intelligence (ZKAI) and Zero-Knowledge Two Factor Authentication (ZK2FA) fields, settling on a common mechanism may even open the doors for “account recovery provider marketplaces” to emerge.
The account recovery approach described in this proposal allows for multiple recovery providers to coexist and provide a wide variety of unique recovery services. In simple terms, smart accounts become “recovery provider aggregators”, making it possible for the users to never rely on centralized services or projects.
The Account Abstraction Recovery Interface (AARI) aims to define a flexible interface for any smart account to implement, allowing users to actively manage their account recovery providers and restore the access of an account in case of a private key loss.
Specification
The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
A smart account willing to support AARI MUST implement the following interface:
pragma solidity ^0.8.20;
/**
* @notice Defines a common account recovery interface for smart accounts to implement.
*/
interface IAccountRecovery {
/**
* MUST be emitted whenever the access of the account changes as a result
* of the account recovery (e.g. in the `recoverAccess` function).
*/
event AccessRecovered(bytes subject);
/**
* MUST be emitted whenever a new recovery provider is added to
* the account (e.g. in the `addRecoveryProvider` function).
*/
event RecoveryProviderAdded(address indexed provider);
/**
* MUST be emitted whenever a recovery provider is removed from
* the account (e.g. in the `removeRecoveryProvider` function).
*/
event RecoveryProviderRemoved(address indexed provider);
/**
* @notice A function to add a new recovery provider.
* SHOULD be access controlled.
* MUST check that `provider` is not `address(0)`.
* MUST call `subscribe` on the `provider`.
* MUST pass `recoveryData` to the `subscribe` function.
*
* @param provider the address of a recovery provider (ZKP verifier) to add.
* @param recoveryData custom data (commitment) for the recovery provider.
*/
function addRecoveryProvider(address provider, bytes memory recoveryData) external payable;
/**
* @notice A function to remove an existing recovery provider.
* SHOULD be access controlled.
* MUST call `unsubscribe` on the `provider`.
*
* @param provider the address of a previously added recovery provider to remove.
*/
function removeRecoveryProvider(address provider) external payable;
/**
* @notice A view function to check if a provider has been previously added.
*
* @param provider the provider to check.
* @return true if the provider exists in the account, false otherwise.
*/
function recoveryProviderAdded(address provider) external view returns (bool);
/**
* @notice A non-view function to recover access of a smart account.
* MUST check that `provider` exists in the account.
* MUST call `recover` on the `provider`.
* MUST update the account access according to `subject` if `proof` verification succeeds.
* MUST return `true` if the access recovery is successful.
*
* @param subject the recovery subject (encoded owner address, access control role, etc).
* @param provider the address of a recovery provider.
* @param proof an encoded proof of recovery (ZKP/ZKAI, signature, etc).
* @return `true` if recovery is successful, `false` (or revert) otherwise.
*/
function recoverAccess(
bytes memory subject,
address provider,
bytes memory proof
) external returns (bool);
}
A recovery provider MUST implement the following interface:
/**
* @notice Defines a common recovery provider interface.
*/
interface IRecoveryProvider {
/**
* MUST be emitted whenever a new account subscribes to
* the recovery provider (e.g. in the `subscribe` function).
*/
event AccountSubscribed(address indexed account);
/**
* MUST be emitted whenever an account unsubscribes from
* the recovery provider (e.g. in the `unsubscribe` function).
*/
event AccountUnsubscribed(address indexed account);
/**
* @notice A function that "subscribes" a smart account (msg.sender) to a recovery provider.
* SHOULD process and assign the `recoveryData` to the `msg.sender`.
*
* @param recoveryData a recovery commitment (hash/ZKP public output) to be used
* in the `recover` function to check a recovery proof validity.
*/
function subscribe(bytes memory recoveryData) external payable;
/**
* @notice A function that revokes a smart account subscription.
* MUST delete all the recovery data associated with the `msg.sender`.
*/
function unsubscribe() external payable;
/**
* @notice A function to get a recovery data (commitment) of an account.
*
* @param account the account to get the recovery data of.
* @return the associated recovery data.
*/
function getRecoveryData(address account) external view returns (bytes memory);
/**
* @notice A function that checks if a recovery of a smart account (msg.sender)
* to the new subject is possible.
* SHOULD use `msg.sender`'s `recoveryData` to check the `proof` validity.
* MUST ensure that the `proof` can't be reused, e.g. update nonce.
*
* @param object the new object (may be different to subject) to recover the `msg.sender` access to.
* @param proof the recovery proof.
*/
function recover(bytes memory object, bytes memory proof) external;
}
Rationale
The AARI is expected to work with any account abstraction standard to allow for maximum account recovery flexibility. Whether it is EIP-4337 or EIP-7702, a particular smart account provider may support account recovery by simply implementing a common interface.
Since the whole account recovery process is nothing but proving the knowledge of some alternative secret to a private key, it is essential for accounts to be able to “commit” to this secret. The subscribe
function in the recovery provider interface allows precisely for that. Moreover, if at some point in time a user wanted to “recommit” to a new secret (due to security reasons), they could multicall unsubscribe
+ subscribe
functions to achieve the desired result.
The recovery functions accept arbitrary bytes as subject
and object
parameters to allow for a variety of access control rules to be recovered, since many smart accounts are ownerless and have no “owner” address to be directly substituted.
Backwards Compatibility
This EIP is fully backwards compatible.
Security Considerations
There are several security concerns to point out:
- It is up to a smart account developer to properly access control
addRecoveryProvider
andremoveRecoveryProvider
functions. - A smart account user may be “phished” to add a malicious recovery provider to their account. In that case, a recovery provider may gain full control over the account by accepting fake recovery proofs.
Copyright
Copyright and related rights waived via CC0.