Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
22 changes: 11 additions & 11 deletions documents/EIP7702DeleGator.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@

## Overview

This document provides an overview of the implemented EIP-7702-compatible contracts. These contracts use a different upgrade mechanism than the previous UUPS proxy-based architecture (as implemented in DeleGatorCore) and instead follow the EIP-7702 standard.
These contracts let an EOA delegate its code to a DeleGator implementation under EIP-7702. EIP-7702 changes code through an EOA authorization and has no initializer.

Under EIP-7702, an Externally Owned Account (EOA) can submit an authorization to map the contract code of an existing contract to that EOA. Unlike UUPS proxy-based contracts, this approach neither supports contract initialization nor relies on UUPS-related code.
## Production Stateless account

## Contracts
`EIP7702DeleGatorCore` and `EIP7702StatelessDeleGator` provide the single-`DelegationManager` account. They support ERC-4337 and require ERC-1271 and UserOperation signatures to recover to the EOA whose address hosts the delegated code.

### 1. EIP7702DeleGatorCore.sol
## EIP7702MultiManagerDeleGator

**EIP7702DeleGatorCore** serves as the foundational contract for EIP-7702-compatible delegator functionality with ERC-7710. It acts as the primary interface for interactions under EIP-7702 and implements the EIP-7821 interface, which provides a method to execute calls in different modes (e.g., single or batch). These methods can be invoked either through the privileged ERC-4337 EntryPoint or directly via the EOA address.
`EIP7702MultiManagerDeleGator` is a non-ERC-4337 account with two immutable default `DelegationManager` contracts and optional additional approved `DelegationManager` contracts.

Future implementations may introduce additional features, such as signature validation, as outlined in EIP-7821.
See the [implementation](../src/EIP7702/EIP7702MultiManagerDeleGator.sol) and [core](../src/EIP7702/EIP7702MultiManagerDeleGatorCore.sol) source for API and implementation behavior.

This contract also integrates OpenZeppelin’s EIP712 functionality. The name and version used in the EIP712 constructor are limited to a maximum of 31 bytes. Exceeding this limit causes those variables to be stored in the contract state without namespace storage, leading to conflicts. Restricting the name and version size helps ensure that **EIP7702DeleGatorCore** remains stateless by avoiding additional storage.
### Security considerations

### 2. EIP7702StatelessDeleGator.sol
> **Warning:** Every default or approved `DelegationManager` is a root authority over the account. It can execute arbitrary calls, self-call the account, and modify mutable manager approvals.

**EIP7702StatelessDeleGator** does not maintain signer data within the contract state. Instead, control is granted to the EOA that shares the same address, in accordance with EIP-7702. The contract can be invoked either through the privileged ERC-4337 EntryPoint or directly via the EOA address. The signature is verified via the `isValidSignature()` function.

This stateless design offers a lightweight and secure approach to delegator functionality under the EIP-7702 standard.
- Unknown, unofficial, unaudited, compromised, or upgradeable `DelegationManager` contracts can compromise the account. Users and integrators must carefully verify and trust each one before configuring or approving it.
- The two default `DelegationManager` contracts cannot be revoked for this implementation.
- Under EIP-7702, changing the delegated implementation does not clear the EOA's storage. Mutable approvals use the ERC-7201 namespace `DeleGator.EIP7702MultiManager.v1`; a replacement implementation should use a different namespace unless it intentionally adopts the same approvals. There is no on-chain enumeration or revoke-all operation.
42 changes: 42 additions & 0 deletions script/DeployEIP7702MultiManagerDeleGator.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT AND Apache-2.0
pragma solidity 0.8.23;

import { Script, console2 } from "forge-std/Script.sol";

import { EIP7702MultiManagerDeleGator } from "../src/EIP7702/EIP7702MultiManagerDeleGator.sol";
import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol";

/**
* @title DeployEIP7702MultiManagerDeleGator
* @notice Deterministically deploys the EIP-7702 multi-DelegationManager implementation.
* @dev Requires SALT, DEFAULT_DELEGATION_MANAGER_1, and DEFAULT_DELEGATION_MANAGER_2 environment variables.
*/
contract DeployEIP7702MultiManagerDeleGator is Script {
bytes32 internal salt;
IDelegationManager internal defaultDelegationManager1;
IDelegationManager internal defaultDelegationManager2;

/// @notice Loads deterministic deployment inputs from the environment.
function setUp() public {
salt = bytes32(abi.encodePacked(vm.envString("SALT")));
defaultDelegationManager1 = IDelegationManager(vm.envAddress("DEFAULT_DELEGATION_MANAGER_1"));
defaultDelegationManager2 = IDelegationManager(vm.envAddress("DEFAULT_DELEGATION_MANAGER_2"));

console2.log("~~~");
console2.log("Deployer: %s", msg.sender);
console2.log("Default DelegationManager 1: %s", address(defaultDelegationManager1));
console2.log("Default DelegationManager 2: %s", address(defaultDelegationManager2));
console2.log("Salt:");
console2.logBytes32(salt);
}

/// @notice Deploys the implementation with CREATE2.
/// @return implementation_ The deployed multi-DelegationManager implementation.
function run() public returns (EIP7702MultiManagerDeleGator implementation_) {
vm.startBroadcast();
implementation_ = new EIP7702MultiManagerDeleGator{ salt: salt }(defaultDelegationManager1, defaultDelegationManager2);
vm.stopBroadcast();

console2.log("EIP7702MultiManagerDeleGatorImpl: %s", address(implementation_));
}
}
13 changes: 13 additions & 0 deletions script/verification/verify-contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ add_contract \
"0x0000000071727De22E5E9d8BAf0edAc6f37da032")" \
""

# EIP7702MultiManagerDeleGator
# No address is committed until an actual deployment exists. Set all three variables to include it.
if [[ -n "${EIP7702_MULTI_MANAGER_ADDRESS:-}" ]]; then
add_contract \
"EIP7702MultiManagerDeleGator" \
"src/EIP7702/EIP7702MultiManagerDeleGator.sol" \
"$EIP7702_MULTI_MANAGER_ADDRESS" \
"$(encode_args "constructor(address,address)" \
"$DEFAULT_DELEGATION_MANAGER_1" \
"$DEFAULT_DELEGATION_MANAGER_2")" \
""
fi

# NativeTokenPaymentEnforcer
add_contract \
"NativeTokenPaymentEnforcer" \
Expand Down
50 changes: 50 additions & 0 deletions src/EIP7702/EIP7702MultiManagerDeleGator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT AND Apache-2.0
pragma solidity 0.8.23;

import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import { EIP7702MultiManagerDeleGatorCore } from "./EIP7702MultiManagerDeleGatorCore.sol";
import { IDelegationManager } from "../interfaces/IDelegationManager.sol";
import { ERC1271Lib } from "../libraries/ERC1271Lib.sol";

/**
* @title EIP7702MultiManagerDeleGator
* @notice EIP-7702 account with two permanent default DelegationManagers and mutable additional DelegationManagers.
* @dev Every default or approved additional DelegationManager has full root execution authority.
*/
contract EIP7702MultiManagerDeleGator is EIP7702MultiManagerDeleGatorCore {
////////////////////////////// State //////////////////////////////

/// @dev The name of the implementation.
string public constant NAME = "EIP7702MultiManagerDeleGator";

/// @dev The implementation version.
string public constant VERSION = "1.0.0";

////////////////////////////// Constructor //////////////////////////////

/**
* @notice Initializes the implementation with two equal, permanent default DelegationManagers.
* @param _defaultDelegationManager1 The first permanent DelegationManager.
* @param _defaultDelegationManager2 The second permanent DelegationManager.
*/
constructor(
IDelegationManager _defaultDelegationManager1,
IDelegationManager _defaultDelegationManager2
)
EIP7702MultiManagerDeleGatorCore(_defaultDelegationManager1, _defaultDelegationManager2)
{ }

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

/**
* @notice Verifies a signature from the EOA whose address hosts this delegated code.
* @param _hash The signed hash.
* @param _signature The ECDSA signature.
* @return The ERC-1271 magic value for a valid signature, otherwise the failure value.
*/
function _isValidSignature(bytes32 _hash, bytes calldata _signature) internal view override returns (bytes4) {
if (ECDSA.recover(_hash, _signature) == address(this)) return ERC1271Lib.EIP1271_MAGIC_VALUE;
return ERC1271Lib.SIG_VALIDATION_FAILED;
}
}
Loading
Loading