---
eip: 7779
title: Interoperable Delegated Accounts
description: Interface for delegated externally owned accounts to enable better redelegation between wallets.
author: David Kim (@PowerStream3604), Richard Meissner (@rmeissner), Akshay Patel (@akshay-ap), Joshua Kim (@LightningHun), Fangting (@trinity-0111), Yoav Weiss (@yoavw)
discussions-to: https://ethereum-magicians.org/t/erc-7779-interoperable-delegated-account/21237
status: Draft
type: Standards Track
category: ERC
created: 2024-10-02
requires: 7201, 7702
---

## Abstract

This proposal outlines the interfaces to make delegated EOAs interoperable after the merge of [EIP-7702](./eip-7702.md). With [EIP-7702](./eip-7702.md), EOAs will be able to enable execution abstraction, which leads to a more feature-rich account, including gas sponsorship, batch execution, and more.

However, there is a need to help facilitate storage management for redelegation, as invalid management of storage may incur storage collisions that can lead to unexpected behavior of accounts (e.g., account getting locked, security vulnerabilities, etc)

The interface `InteroperableDelegatedAccount` suggests the interfaces for delegated EOAs to be interoperable and facilitate a better environment for redelegation.

## Motivation

After the merge of [EIP-7702](./eip-7702.md), it is expected that a considerable number of EOA wallets will migrate from pure EOA accounts to delegated EOA accounts.

This is to enable a more appealing wallet UX, including a 1-step swap, automated subscription, gas sponsorship, and more.

However, considering the fact that delegated EOAs will utilize its own storage bound to their Smart Account implementation, the storage management is essential to foster migration between wallets to better ensure sovereignty of users to freely migrate their wallet app whenever they want.

EOA (Externally Owned Account) is currently comprised of cryptographic key pair that is mostly managed in the form of mnemonic phrase.

This simplicity provided frictionless interoperability between wallets that gave users the freedom to freely migrate between different wallet applications.

However, after the merge of [EIP-7702](./eip-7702.md), each EOA will be given the ability to delegate itself to a smart account which will impact migration as storage remains in the continuous context while EOA can be delegated to diverse smart accounts if the user migrates their wallet.

Account Abstraction Wallets, given the wallet-specific validation and execution logic, also have the interoperability issue to be considered but its importance in EOA is much more significant as EOA users are already familiar with wallet migration and its a common action to migrate wallets.

This spec provides a standard approach for fetching the storage base used in the delegated account together with an optional mechanism to clean up the storage.

Moreover, it is worth noting that this spec is not limited to [EIP-7702](./eip-7702.md) based smart accounts but smart accounts and smart contracts in general that uses a custom storage slot.

## Specification

The keywords "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.

```solidity
interface IInteroperableDelegatedAccount {

	/*
	 * @dev    Provides the namespace of the account.
	 *         namespace of accounts can possibly include, account version, account name, wallet vendor name, etc
	 * @notice this standard does not standardize the namespace format
	 * e.g.,   "v0.1.2.7702Account.WalletProjectA"
	 */
	function accountId() external view returns (string);
	
	/*
	 * @dev    Externally shares the storage bases that has been used throughout the account.
	 *         Majority of 7702 accounts will have their distinctive storage base to reduce the chance of storage collision.
	 *         This allows the external entities to know what the storage base is of the account.
	 *         Wallets willing to redelegate already-delegated accounts should call accountStorageBase() to check if it confirms with the account it plans to redelegate.
	 *
	 *         The bytes32 array should be stored at the storage slot: keccak(keccak('InteroperableDelegatedAccount.ERC.Storage')-1) & ~0xff
	 *         This is an append-only array so newly redelegated accounts should not overwrite the storage at this slot, but just append their base to the array.
	 *         This append operation should be done during the initialization of the account.
	 * 		   This array should return a value of keccak hash unless using external storage.
	 */
	function accountStorageBases() external view returns (bytes32[]);

}
```

```solidity
interface IRedelegableDelegatedAccount {

	/*
	 * @dev    Function called before redelegation.
	 *         This function should prepare the account for a delegation to a different implementation.
	 *         This function could be triggered by the new wallet that wants to redelegate an already delegated EOA.
	 *         It should uninitialize storages if needed and execute wallet-specific logic to prepare for redelegation.
	 *         msg.sender should be the owner of the account.
	 */
	function onRedelegation() external returns (bool);

}
```

Accounts MUST implement the `IInteroperableDelegatedAccount` to be compliant with the standard.

Accounts MUST use `keccak256()` to compute the storage bases for `accountStorageBases()`, unless using external storage contract.

Accounts MAY implement the `IRedelegableDelegatedAccount`.

### `accountId()`

This function is a view function to fetch the account information.

A use case for this could be wallet showing the redelegation process e.g., Are you willing to migrate your account `“Wallet A” → “Wallet B”`.

Wallet A information could be extracted from `accountId()`.

### `accountStorageBases()`

This function returns the list of base storage slots of that account has used.

To comply with this standard, the account MUST use `keccak256()` to prevent collision when calculating the storage slot.

EIP-7702 Accounts do plan to use a custom non-zero storage slot to avoid storage collision as much as possible, however, there hasn’t been a standardized approach on how to fetch them.

This function provides a standardized approach for wallets and other applications to check the base storage slots of an account, and verify if the base storage slots are far enough from the newly to-be-redelegated account’s base storage slot.

Note that there could be some exceptions for mappings, etc depending on how account manages storage.

This provides Wallets and applications a standard approach to fetch the base storage slots for verification rather than just relying on the probability of hash.

If the account uses external storage, it should return ERC Number prefixed slot with the external storage contract address concatenated.

```solidity
<ERC-Number><ERC-Number><ERC-Number>..N...<Storage-Contract-Address>
```
For example, if the storage contract address is `0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA` the returned value should be
```
0x777977797779777977797779AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
```

When the account is delegated(e.g., during the account initialization stage), the account implementation should append the base storage slot of the account to the following slot position: `keccak(keccak('InteroperableDelegatedAccount.ERC.Storage')-1) & ~0xff` .

The storage variable would be using the `bytes32[]` type and is an append-only variable which newly delegated accounts append its storage slot hash. The account may choose to not append its storage base to an array if there is an identical entry that already exist.

In case the account identifies that there are colliding storage bases, the account can perform further storage verification either off-chain or on-chain and decide whether the delegation would happen.

Wallet may revert the delegation if the colliding storage includes a suspicious storage values that may target the user(e.g., shadow signer, etc).

### `onRedelegation()`

This function is to prepare for the redelegation to a new account.

When this function is called, the existing delegated account should perform actions to not limit or impact the user when the user redelegates to a new account as much as possible.

For example, the account could uninitialize the storage variables as much as it can to provide clean storage for new wallet.

This standard, however, does not explicitly state the behavior to be done during this function call as wallet implementations have very distinctive architecture and details.

**The standard expect the wallet implementation to revert it back to a clean storage state ***as much as possible*** with this function.**

`onRedelegation()` should validate if the caller is indeed the authorized user by checking the `msg.sender` value.

This could also be done through a "self-call" if a custom validation scheme is implemented or at the wallet's discretion as a side case.

![diagram showing the flow of onredelegation](../assets/eip-7779/diagram.svg)

## Rationale

### Storage base checks

This standard is designed with the need of wallets to validate the storage of the EOA, even if some may consider that the probability of hash is already big that the account doesn't have to check, assuming that each wallet uses a different storage base slot.
In fact, this standard thinks exactly the opposite. It is worth scanning the storage, or at least the storage that the delegated account will use, which the wallet wants to delegate to. E.g., Just like developers validating the storage of Facets in Diamond ([ERC-2535](./eip-2535.md)) to prevent storage collision and not just relying on hash probability.
In line with this, the `accountStorageBases()` was designed to not only return the storage base of the current wallet implementation, but return the full historical storage slots that the account has used.
This could provide valuable information for the storage scanning of the EOA before delegation.

### Optional `onRedelegation()`

`onRedelegation()` was designed to be optional to lower the barrier of being compliant with this standard. Also, there could be accounts that does not functionally require a hook-logic to be in place before redelegation, or accounts that does not suite with the design principle of the `onRedelegation()` e.g., excessive use of mapping or data types that's hard to uninitialize.

It is worth noting that, `onRedelegation()` does not obligate the account to completely whipe out it's storage. It's more of a best effort function to leave the cleanest stage for the future use of the EOA in a new wallet. Or to execute a function to prepare for redelegation.

## Backwards Compatibility

Existing smart accounts that was built prior to the [EIP-7702](./eip-7702.md) discussion will need changes to support this standard.

This standard was specifically for Smart Accounts for EOA, but this could be applied further to diverse cases and architecture.

## Security Considerations

1. Calling `onRedelegation()` should include security mechanism to properly authentication the owner.
2. This standard enforces the accounts to 
    1. provide proper Base Storage Slot when `accountStorageBase()` is called
    2. perform proper actions to make account storage to a clean state as much as possible (e.g., uninitialization of storage variables, etc) IF the account supports `onRedelegation()`
    
    However, whether the account follows the above three enforcements with behavioral actions is dependant of the account.
    
    If needed, accounts may check the authenticity of the information through off-chain approaches.
    
3. Wiping out the storage completely may not be an adaptable action depending on how account implementation manages storage.
    
    This standard recommends the account to completely wipe out its storage, however, exceptions apply if the account is incapable of doing that.
    
    In the case when the account cannot completely wipe out its storage, the standard expect the account to perform the best degree of action it can do to support the redelegation operation for the user.
    
    Also, the account should make sure the initializer cannot be triggered by an arbitrary entity after `onRedelegation()` is called.
    
4. `onRedelegation()` should not reset the replay protection considering that it could incur a vulnerability(e.g., signature reply attack).

5. It is worth noting that this standard is an ERC, which means that even if the ERC enforces it, the actual implementation may not be compliant with it. e.g., accounts pretending to support this standard which is not, in fact. So it is recommend to validate if the account is a know implementation that is secure and compliant with the standard.

6. The standard ENFORCES the storage slot to be calculated through `keccak256()` to reduce collision. The preimage of the hash could be the name/version or a combination, it is under full discretion of the account.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).