Skip to content

Update ERC-7710: Improved ERC in response to feedback on ethereum magicians #982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 57 additions & 3 deletions ERCS/erc-7710.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@
interactions limits the ability to adapt to new requirements or to delegate specific, limited permissions in a dynamic
manner.

Additionally, the need to repeatedly sign messages for each interaction creates friction in user experiences, particularly in scenarios requiring frequent or automated interactions.

The proposed standard aims to solve these challenges by enabling the creation of long-lived sessions and delegated permissions through a single signature. These delegations can be used to:
- Establish persistent sessions with dApps that don't require repeated signing
- Grant bounded permissions to AI agents or automated systems
- Create shareable invite links with specific capabilities
- Enable third-party delegates to act within well-defined policy constraints

By allowing the creation of open-ended yet policy-constrained delegations with a single signature, this standard helps
minimize user interactions while maximizing their meaningful content. Users can grant specific capabilities with
clear boundaries, rather than repeatedly signing similar permissions.

The proposed standard aims to simplify and standardize the process of delegation between contracts, reducing the
operational complexity and gas costs associated with shared capabilities. By establishing a common framework for
delegating permissions, we can streamline interactions within the Ethereum ecosystem, making contracts more flexible,
Expand All @@ -51,12 +63,15 @@
### Terms

- A **Delegator** is a smart contract that can create a delegation.
- A **Delegation Manager** is a singleton smart contract that is responsible for validating delegation authority and
calling on the *Delegator* to execute an action. It implements the `ERC7710Manager` interface.
- A **Delegation Manager** is a smart contract that validates delegation authority and calls on the *Delegator* to execute an action. It implements the `ERC7710Manager` interface. A Delegation Manager verifies and processes delegation redemptions, and multiple Delegation Managers can exist with different implementations. A contract account can be its own delegation manager.
- A **delegation** is an authority given to another address to perform a specific action.
- A **delegate** is a smart contract, smart contract account, or EOA that has authority to redeem a delegation.
- A **redeemer** is a *delegate* that is using a delegation.

### Obtaining Delegations

The process by which a delegate obtains a delegation is intentionally left out of scope for this ERC. This ERC focuses solely on the interface for redeeming delegations and the validation of delegation authority. The mechanism for requesting and granting delegations may be implemented in various ways depending on the use case, such as through [ERC-7715](./eip-7715.md) or other protocols. This separation of concerns allows for flexibility in how delegations are created while maintaining a consistent interface for their redemption.

### Overview

#### Redeeming a Delegation
Expand All @@ -80,6 +95,18 @@

The bytes32 array `_modes` and the bytes array `_executionCallDatas` passed in as parameters to the `redeemDelegations` function are arrays of `mode` and `executionCalldata`, which are defined precisely in [ERC-7579](./eip-7579.md) (under the "Execution Behavior" section). Briefly, `mode` encodes the "behavior" of the execution, which could be a single call, a batch call, and others. `executionCallData` encodes the data of the execution, which typically includes at least a `target`, a `value`, and a `to` address.

The three arrays MUST be interpreted as a list of tuples, where each tuple consists of (`_permissionContexts[i]`, `_modes[i]`, `_executionCallDatas[i]`). The function MUST revert if the arrays have different lengths. Each tuple represents a single delegation redemption with its associated permission context, execution mode, and execution data. Implementations MUST enforce atomicity of the batch.

#### Permission Verification

While this interface does not include an explicit method for checking delegation permissions, dApps SHOULD verify permissions before attempting to execute actions by:

1. Simulating the `redeemDelegations` call with the intended parameters
2. Using the simulation results to determine if the delegation would succeed
3. If the simulation fails, the dApp can request new or updated permissions from the user

This simulation-based approach provides stronger guarantees than a method exposed by the delegation manager, as it validates the entire execution context rather than the claims of the delegation manager.

```solidity
pragma solidity 0.8.23;

Expand All @@ -96,7 +123,11 @@
* @param _modes the array of modes to execute the related executioncallData
* @param _executionCallDatas the array of encoded executions to be executed
*/
function redeemDelegations(bytes[] calldata _permissionContexts, bytes32[] calldata _modes, bytes[] calldata _executionCallDatas) external;
function redeemDelegations(
bytes[] calldata _permissionContexts,
bytes32[] calldata _modes,
bytes[] calldata _executionCallData
) external;
}
```

Expand Down Expand Up @@ -140,13 +171,36 @@
within the context of modular smart accounts: defining a standardized execution interface that can support many types of
executions.

## Reference Implementation

For a minimal reference implementation focusing on delegation redemption, please see [Example7710Manager](../assets/erc-7710/Example7710Manager.sol).

For a complete reference implementation of a Delegation Manager, see the MetaMask Delegation Framework, which includes features such as:

- EIP-712 signature validation for delegations

Check failure on line 180 in ERCS/erc-7710.md

View workflow job for this annotation

GitHub Actions / EIP Walidator

the first match of the given pattern must be a link

error[markdown-link-first]: the first match of the given pattern must be a link --> ERCS/erc-7710.md | 180 | - EIP-712 signature validation for delegations | = info: the pattern in question: `(?i)(?:eip|erc)-([0-9])+` = help: see https://ethereum.github.io/eipw/markdown-link-first/
- Support for both EOA and contract signatures (ERC-1271)
- Caveat enforcement for fine-grained delegation control
- Batch delegation processing
- Delegation revocation mechanisms

The MetaMask implementation demonstrates one way to build a robust delegation system while adhering to this standard's interface requirements.

## Security Considerations

The introduction of customizable authorization terms requires careful consideration of how authorization data is
structured and interpreted. Potential security risks include the misinterpretation of authorization terms and
unauthorized actions being taken if the interface is not properly implemented. It is recommended that applications
implementing this interface undergo thorough security audits to ensure that authorization terms are handled securely.

### Permission Verification

dApps MUST NOT assume that having received a delegation in the past guarantees future execution rights. Delegations can be revoked, expire, or become invalid due to state changes. To ensure reliable operation:

1. Always simulate delegation redemptions before submitting them on-chain
2. Handle simulation failures gracefully by requesting new permissions when needed
3. Consider implementing retry logic with escalating permission requests
4. Be prepared for delegations to become invalid between simulation and execution

Needs discussion. <!-- TODO -->

## Copyright
Expand Down
133 changes: 133 additions & 0 deletions assets/erc-7710/Example7710Manager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { IERC7579Account } from "../erc-7579/IMSA.sol";

/**
* @title Example7710Manager
* @notice Not for production use.A minimal reference implementation for ERC-7710 focusing on delegation redemption.
* @dev This is an intentionally simplified implementation to demonstrate core concepts.
* For a complete production implementation with features like conditional permission enforcement and revocation, see MetaMask's Delegation Framework:
* https://github.com/MetaMask/delegation-framework/blob/main/src/DelegationManager.sol
*/
contract Example7710Manager {
////////////////////////////// Types //////////////////////////////

struct Delegation {
address delegator; // The address delegating authority
address delegate; // The address receiving authority
bytes32 authority; // The authority being delegated (or ROOT_AUTHORITY)
bytes signature; // The delegator's signature authorizing this delegation
}

////////////////////////////// Errors //////////////////////////////

error TupleDataLengthMismatch();
error InvalidDelegate();
error InvalidAuthority();
error InvalidSignature();

////////////////////////////// Constants //////////////////////////////

/// @dev Special authority value indicating the delegator is the root authority
bytes32 public constant ROOT_AUTHORITY = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;

////////////////////////////// External Methods //////////////////////////////

/**
* @notice Validates and executes delegated actions through a chain of authority.
* @param _permissionContexts Array of delegation chains, each ordered from leaf to root.
* Each chain demonstrates authority where:
* - Index 0 is the leaf delegation (msg.sender's authority)
* - Each delegation points to its authority via the previous delegation's hash
* - The last delegation must have ROOT_AUTHORITY
* @param _modes Execution modes for each action (see ERC-7579)
* @param _executionCallDatas Encoded actions to execute
*/
function redeemDelegations(
bytes[] calldata _permissionContexts,
bytes32[] calldata _modes,
bytes[] calldata _executionCallDatas
) external {
uint256 batchSize_ = _permissionContexts.length;
if (batchSize_ != _executionCallDatas.length || batchSize_ != _modes.length) {
revert TupleDataLengthMismatch();
}

Delegation[][] memory batchDelegations_ = new Delegation[][](batchSize_);

// Process each batch
for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) {
Delegation[] memory delegations_ = abi.decode(_permissionContexts[batchIndex_], (Delegation[]));

batchDelegations_[batchIndex_] = delegations_;

// Validate caller is the delegate
if (delegations_[0].delegate != msg.sender) {
revert InvalidDelegate();
}

// Validate each delegation in chain
for (uint256 i = 0; i < delegations_.length; i++) {
Delegation memory delegation_ = delegations_[i];
bytes32 delegationHash_ = _getDelegationHash(delegation_);

// Note: In a production implementation, you would want to use EIP-712 for typed data signing
// and proper signature validation for both EOA and contract signatures.
// This is simplified for demonstration purposes.
if (!_isValidSignature(delegationHash_, delegation_.signature, delegation_.delegator)) {
revert InvalidSignature();
}

// Validate authority chain
if (i != delegations_.length - 1) {
if (delegation_.authority != _getDelegationHash(delegations_[i + 1])) {
revert InvalidAuthority();
}
// Validate delegate chain
address nextDelegate_ = delegations_[i + 1].delegate;
if (delegation_.delegator != nextDelegate_) {
revert InvalidDelegate();
}
} else if (delegation_.authority != ROOT_AUTHORITY) {
revert InvalidAuthority();
}
}

// Execute the delegated action on the root delegator
IERC7579Account(delegations_[delegations_.length - 1].delegator).executeFromExecutor(
_modes[batchIndex_],
_executionCallDatas[batchIndex_]
);
}
}

////////////////////////////// Internal Methods //////////////////////////////

/**
* @notice Creates a simple hash of a Delegation struct
* @dev In production, use EIP-712 for typed data hashing
*/
function _getDelegationHash(Delegation memory delegation) internal pure returns (bytes32) {
return keccak256(abi.encode(
delegation.delegator,
delegation.delegate,
delegation.authority
));
}

/**
* @notice Basic signature validation (simplified for example purposes)
* @dev In production, use EIP-712 and proper signature validation
*/
function _isValidSignature(
bytes32 hash,
bytes memory signature,
address signer
) internal pure returns (bool) {
// ECDSA recover
// or ERC1271 isValidSignature
// Logic would go here
return true; // Simplified for example
}
}
Loading