Skip to content
Merged
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
4 changes: 2 additions & 2 deletions certora/harnesses/AccountHarness.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {AccountERC7702WithModulesMock} from "../patched/mocks/account/AccountMock.sol";
import {AccountEIP7702WithModulesMock} from "../patched/mocks/account/AccountMock.sol";
import {EIP712} from "../patched/utils/cryptography/EIP712.sol";
import {EnumerableSet} from "../patched/utils/structs/EnumerableSet.sol";

contract AccountHarness is AccountERC7702WithModulesMock {
contract AccountHarness is AccountEIP7702WithModulesMock {
using EnumerableSet for EnumerableSet.AddressSet;

constructor(string memory name, string memory version) EIP712(name, version) {}
Expand Down
2 changes: 1 addition & 1 deletion contracts/account/extensions/draft-AccountERC7579.sol
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ abstract contract AccountERC7579 is Account, IERC1271, IERC7579Execution, IERC75
* actual copy. However, this would require `_installModule` to get a calldata bytes object instead of a memory
* bytes object. This would prevent calling `_installModule` from a contract constructor and would force the use
* of external initializers. That may change in the future, as most accounts will probably be deployed as
* clones/proxy/ERC-7702 delegates and therefore rely on initializers anyway.
* clones/proxy/EIP-7702 delegates and therefore rely on initializers anyway.
*/
function _decodeFallbackData(
bytes memory data
Expand Down
2 changes: 1 addition & 1 deletion contracts/account/utils/EIP7702Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pragma solidity ^0.8.20;
/**
* @dev Library with common EIP-7702 utility functions.
*
* See https://eips.ethereum.org/EIPS/eip-7702[ERC-7702].
* See https://eips.ethereum.org/EIPS/eip-7702[EIP-7702].
*/
library EIP7702Utils {
bytes3 internal constant EIP7702_PREFIX = 0xef0100;
Expand Down
6 changes: 3 additions & 3 deletions contracts/mocks/account/AccountMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ abstract contract AccountWebAuthnMock is Account, SignerWebAuthn, ERC7739, ERC78
}
}

abstract contract AccountERC7702Mock is Account, SignerEIP7702, ERC7739, ERC7821, ERC721Holder, ERC1155Holder {
abstract contract AccountEIP7702Mock is Account, SignerEIP7702, ERC7739, ERC7821, ERC721Holder, ERC1155Holder {
/// @inheritdoc ERC7821
function _erc7821AuthorizedExecutor(
address caller,
Expand All @@ -92,7 +92,7 @@ abstract contract AccountERC7702Mock is Account, SignerEIP7702, ERC7739, ERC7821
}
}

abstract contract AccountERC7702WithModulesMock is
abstract contract AccountEIP7702WithModulesMock is
Account,
AccountERC7579,
SignerEIP7702,
Expand All @@ -119,7 +119,7 @@ abstract contract AccountERC7702WithModulesMock is
return erc7739magic == bytes4(0xffffffff) ? AccountERC7579.isValidSignature(hash, signature) : erc7739magic;
}

/// @dev Enable signature using the ERC-7702 signer.
/// @dev Enable signature using the EIP-7702 signer.
function _rawSignatureValidation(
bytes32 hash,
bytes calldata signature
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// contracts/MyAccountERC7702.sol
// contracts/MyAccountEIP7702.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

Expand All @@ -8,7 +8,7 @@ import {ERC1155Holder} from "../../../token/ERC1155/utils/ERC1155Holder.sol";
import {ERC7821} from "../../../account/extensions/draft-ERC7821.sol";
import {SignerEIP7702} from "../../../utils/cryptography/signers/SignerEIP7702.sol";

contract MyAccountERC7702 is Account, SignerEIP7702, ERC7821, ERC721Holder, ERC1155Holder {
contract MyAccountEIP7702 is Account, SignerEIP7702, ERC7821, ERC721Holder, ERC1155Holder {
/// @dev Allows the entry point as an authorized executor.
function _erc7821AuthorizedExecutor(
address caller,
Expand Down
2 changes: 1 addition & 1 deletion contracts/utils/cryptography/signers/SignerEIP7702.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {AbstractSigner} from "./AbstractSigner.sol";
import {ECDSA} from "../ECDSA.sol";

/**
* @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for ERC-7702 accounts.
* @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for EIP-7702 accounts.
*
* @custom:stateless
*/
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/accounts.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] lets EOAs delegate to smart co

The signature verification stays compatible: delegated EOAs are treated as contracts using ERC-1271, making it easy to redelegate to a contract with ERC-1271 support with little overhead by reusing the validation mechanism of the account.

TIP: Learn more about delegating to an ERC-7702 account in our xref:eoa-delegation.adoc[EOA Delegation] section.
TIP: Learn more about delegating to an EIP-7702 account in our xref:eoa-delegation.adoc[EOA Delegation] section.

=== ERC-7579 Modules

Expand Down
4 changes: 2 additions & 2 deletions docs/modules/ROOT/pages/eoa-delegation.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ https://eips.ethereum.org/EIPS/eip-7702[EIP-7702] introduces a new transaction t
* Sponsoring transactions for other users.
* Implementing privilege de-escalation (e.g., sub-keys with limited permissions)

This section walks you through the process of delegating an EOA to a contract following https://eips.ethereum.org/EIPS/eip-7702[ERC-7702]. This allows you to use your EOA's private key to sign and execute operations with custom execution logic. Combined with https://eips.ethereum.org/EIPS/eip-4337[ERC-4337] infrastructure, users can achieve gas sponsoring through https://docs.openzeppelin.com/community-contracts/paymasters[paymasters].
This section walks you through the process of delegating an EOA to a contract following https://eips.ethereum.org/EIPS/eip-7702[EIP-7702]. This allows you to use your EOA's private key to sign and execute operations with custom execution logic. Combined with https://eips.ethereum.org/EIPS/eip-4337[ERC-4337] infrastructure, users can achieve gas sponsoring through https://docs.openzeppelin.com/community-contracts/paymasters[paymasters].

== Delegating execution

EIP-7702 enables EOAs to delegate their execution capabilities to smart contracts, effectively bridging the gap between traditional and xref:accounts.adoc[Smart Accounts]. The xref:api:utils/cryptography.adoc#[`SignerEIP7702`] utility facilitates this delegation by verifying signatures against the EOA's address (`address(this)`), making it easier to implement EIP-7702 in smart contract accounts.

[source,solidity]
----
include::api:example$account/MyAccountERC7702.sol[]
include::api:example$account/MyAccountEIP7702.sol[]
----

TIP: Users can delegate to an instance of xref:api:account.adoc#ERC7821[`ERC-7821`] for a minimal batch executor that does not use ERC-4337 related code.
Expand Down
16 changes: 8 additions & 8 deletions scripts/upgradeable/upgradeable.patch
Original file line number Diff line number Diff line change
Expand Up @@ -361,30 +361,30 @@ index 304d1386a..a1cd63bee 100644
-@openzeppelin/contracts/=contracts/
+@openzeppelin/contracts-upgradeable/=contracts/
+@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
diff --git a/test/account/AccountERC7702.test.js b/test/account/AccountERC7702.test.js
diff --git a/test/account/AccountEIP7702.test.js b/test/account/AccountEIP7702.test.js
index f442d49af..8f22dc926 100644
--- a/test/account/AccountERC7702.test.js
+++ b/test/account/AccountERC7702.test.js
--- a/test/account/AccountEIP7702.test.js
+++ b/test/account/AccountEIP7702.test.js
@@ -26,8 +26,8 @@ async function fixture() {

// domain cannot be fetched using getDomain(mock) before the mock is deployed
const domain = {
- name: 'AccountERC7702Mock',
- name: 'AccountEIP7702Mock',
- version: '1',
+ name: '', // Not initialized in the context of signer
+ version: '', // Not initialized in the context of signer
chainId: entrypointDomain.chainId,
verifyingContract: mock.address,
};
diff --git a/test/account/examples/AccountERC7702WithModulesMock.test.js b/test/account/examples/AccountERC7702WithModulesMock.test.js
diff --git a/test/account/examples/AccountEIP7702WithModulesMock.test.js b/test/account/examples/AccountEIP7702WithModulesMock.test.js
index 8ceab19d1..c3f4194a6 100644
--- a/test/account/examples/AccountERC7702WithModulesMock.test.js
+++ b/test/account/examples/AccountERC7702WithModulesMock.test.js
--- a/test/account/examples/AccountEIP7702WithModulesMock.test.js
+++ b/test/account/examples/AccountEIP7702WithModulesMock.test.js
@@ -36,8 +36,8 @@ async function fixture() {

// domain cannot be fetched using getDomain(mock) before the mock is deployed
const domain = {
- name: 'AccountERC7702WithModulesMock',
- name: 'AccountEIP7702WithModulesMock',
- version: '1',
+ name: '', // Not initialized in the context of signer
+ version: '', // Not initialized in the context of signer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.20;

import {Test} from "forge-std/Test.sol";
import {AccountERC7702Mock} from "@openzeppelin/contracts/mocks/account/AccountMock.sol";
import {AccountEIP7702Mock} from "@openzeppelin/contracts/mocks/account/AccountMock.sol";
import {CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {
Expand All @@ -17,11 +17,11 @@ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {PackedUserOperation} from "@openzeppelin/contracts/interfaces/draft-IERC4337.sol";
import {ERC7821} from "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol";

contract AccountERC7702MockConstructor is AccountERC7702Mock {
contract AccountEIP7702MockConstructor is AccountEIP7702Mock {
constructor() EIP712("MyAccount", "1") {}
}

contract AccountERC7702Test is Test {
contract AccountEIP7702Test is Test {
using ERC7579Utils for *;
using ERC4337Utils for PackedUserOperation;
using Strings for *;
Expand All @@ -33,19 +33,19 @@ contract AccountERC7702Test is Test {

// ERC-4337 signer
uint256 private _signerPrivateKey;
AccountERC7702MockConstructor private _signer;
AccountEIP7702MockConstructor private _signer;

function setUp() public {
// Deploy target contract
_target = new CallReceiverMock();

// Setup signer
_signerPrivateKey = 0x1234;
_signer = AccountERC7702MockConstructor(payable(vm.addr(_signerPrivateKey)));
_signer = AccountEIP7702MockConstructor(payable(vm.addr(_signerPrivateKey)));
vm.deal(address(_signer), MAX_ETH);

// Sign and attach delegation
vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey);
vm.signAndAttachDelegation(address(new AccountEIP7702MockConstructor()), _signerPrivateKey);

// Setup entrypoint
address entrypoint = address(ERC4337Utils.ENTRYPOINT_V08);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ async function fixture() {

// ERC-4337 account
const helper = new ERC4337Helper();
const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer });
const mock = await helper.newAccount('$AccountEIP7702Mock', ['AccountEIP7702Mock', '1'], { eip7702signer: signer });

// ERC-4337 Entrypoint domain
const entrypointDomain = await getDomain(predeploy.entrypoint.v08);

// domain cannot be fetched using getDomain(mock) before the mock is deployed
const domain = {
name: 'AccountERC7702Mock',
name: 'AccountEIP7702Mock',
version: '1',
chainId: entrypointDomain.chainId,
verifyingContract: mock.address,
Expand All @@ -40,7 +40,7 @@ async function fixture() {
return { helper, mock, domain, signer, target, beneficiary, other, signUserOp };
}

describe('AccountERC7702', function () {
describe('AccountEIP7702', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ async function fixture() {

// ERC-4337 account
const helper = new ERC4337Helper();
const mock = await helper.newAccount('$AccountERC7702WithModulesMock', ['AccountERC7702WithModulesMock', '1'], {
erc7702signer: eoa,
const mock = await helper.newAccount('$AccountEIP7702WithModulesMock', ['AccountEIP7702WithModulesMock', '1'], {
eip7702signer: eoa,
});

// ERC-4337 Entrypoint domain
const entrypointDomain = await getDomain(predeploy.entrypoint.v08);

// domain cannot be fetched using getDomain(mock) before the mock is deployed
const domain = {
name: 'AccountERC7702WithModulesMock',
name: 'AccountEIP7702WithModulesMock',
version: '1',
chainId: entrypointDomain.chainId,
verifyingContract: mock.address,
Expand All @@ -45,12 +45,12 @@ async function fixture() {
return { helper, validator, mock, domain, entrypointDomain, eoa, target, anotherTarget, beneficiary, other };
}

describe('AccountERC7702WithModules: ERC-7702 account with ERC-7579 modules supports', function () {
describe('AccountEIP7702WithModules: EIP-7702 account with ERC-7579 modules supports', function () {
beforeEach(async function () {
Object.assign(this, await loadFixture(fixture));
});

describe('using ERC-7702 signer', function () {
describe('using EIP-7702 signer', function () {
beforeEach(async function () {
this.signer = this.eoa;
this.signUserOp = userOp =>
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('AccountERC7702WithModules: ERC-7702 account with ERC-7579 modules supp
// Use the first 20 bytes from the nonce key (24 bytes) to identify the validator module
this.userOp = { nonce: ethers.zeroPadBytes(ethers.hexlify(this.validator.target), 32) };

// Deploy (using ERC-7702) and add the validator module using EOA
// Deploy (using EIP-7702) and add the validator module using EOA
await this.mock.deploy();
await this.mock.connect(this.eoa).installModule(MODULE_TYPE_VALIDATOR, this.validator, this.signer.address);
});
Expand Down
10 changes: 5 additions & 5 deletions test/helpers/erc4337.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ class ERC4337Helper {

const accountFactory = await ethers.getContractFactory(name);

if (params.erc7702signer) {
if (params.eip7702signer) {
const delegate = await accountFactory.deploy(...extraArgs);
const instance = await params.erc7702signer.getAddress().then(address => accountFactory.attach(address));
const authorization = await params.erc7702signer.authorize({ address: delegate.target });
return new ERC7702SmartAccount(instance, authorization, env);
const instance = await params.eip7702signer.getAddress().then(address => accountFactory.attach(address));
const authorization = await params.eip7702signer.authorize({ address: delegate.target });
return new EIP7702SmartAccount(instance, authorization, env);
} else {
const initCode = await accountFactory
.getDeployTransaction(...extraArgs)
Expand Down Expand Up @@ -163,7 +163,7 @@ class SmartAccount extends ethers.BaseContract {
}
}

class ERC7702SmartAccount extends SmartAccount {
class EIP7702SmartAccount extends SmartAccount {
constructor(instance, authorization, env) {
super(instance, undefined, env);
this.authorization = authorization;
Expand Down