Skip to content

Commit

Permalink
feat: separate out execution install delegate from constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
adamegyed committed Nov 22, 2024
1 parent af13fcf commit 005856d
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 40 deletions.
14 changes: 7 additions & 7 deletions gas-snapshots/ModularAccount.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"Runtime_AccountCreation": "176147",
"Runtime_BatchTransfers": "93000",
"Runtime_Erc20Transfer": "78454",
"Runtime_InstallSessionKey_Case1": "423148",
"Runtime_InstallSessionKey_Case1": "423172",
"Runtime_NativeTransfer": "54603",
"Runtime_UseSessionKey_Case1_Counter": "78606",
"Runtime_UseSessionKey_Case1_Token": "111919",
"UserOp_BatchTransfers": "198335",
"UserOp_Erc20Transfer": "185331",
"UserOp_BatchTransfers": "198311",
"UserOp_Erc20Transfer": "185319",
"UserOp_InstallSessionKey_Case1": "531355",
"UserOp_NativeTransfer": "161588",
"UserOp_UseSessionKey_Case1_Counter": "195233",
"UserOp_UseSessionKey_Case1_Token": "226217",
"UserOp_deferredValidation": "258080"
"UserOp_NativeTransfer": "161576",
"UserOp_UseSessionKey_Case1_Counter": "195221",
"UserOp_UseSessionKey_Case1_Token": "226205",
"UserOp_deferredValidation": "258068"
}
8 changes: 4 additions & 4 deletions gas-snapshots/SemiModularAccount.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"Runtime_AccountCreation": "97767",
"Runtime_BatchTransfers": "88986",
"Runtime_Erc20Transfer": "74488",
"Runtime_InstallSessionKey_Case1": "421700",
"Runtime_InstallSessionKey_Case1": "421724",
"Runtime_NativeTransfer": "50647",
"Runtime_UseSessionKey_Case1_Counter": "78956",
"Runtime_UseSessionKey_Case1_Token": "112269",
"UserOp_BatchTransfers": "193491",
"UserOp_Erc20Transfer": "180558",
"UserOp_InstallSessionKey_Case1": "528878",
"UserOp_Erc20Transfer": "180546",
"UserOp_InstallSessionKey_Case1": "528890",
"UserOp_NativeTransfer": "156833",
"UserOp_UseSessionKey_Case1_Counter": "195473",
"UserOp_UseSessionKey_Case1_Token": "226457",
"UserOp_deferredValidation": "254131"
"UserOp_deferredValidation": "254119"
}
7 changes: 5 additions & 2 deletions gas/modular-account/ModularAccountBenchmarkBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {ModularAccountBase} from "../../src/account/ModularAccountBase.sol";
import {SemiModularAccountBytecode} from "../../src/account/SemiModularAccountBytecode.sol";
import {AccountFactory} from "../../src/factory/AccountFactory.sol";
import {FALLBACK_VALIDATION} from "../../src/helpers/Constants.sol";
import {ExecutionInstallDelegate} from "../../src/helpers/ExecutionInstallDelegate.sol";
import {AllowlistModule} from "../../src/modules/permissions/AllowlistModule.sol";
import {TimeRangeModule} from "../../src/modules/permissions/TimeRangeModule.sol";
import {SingleSignerValidationModule} from "../../src/modules/validation/SingleSignerValidationModule.sol";
Expand All @@ -34,6 +35,7 @@ abstract contract ModularAccountBenchmarkBase is BenchmarkBase, ModuleSignatureU
ModularAccount public accountImpl;
SemiModularAccountBytecode public semiModularImpl;
SingleSignerValidationModule public singleSignerValidationModule;
ExecutionInstallDelegate public executionInstallDelegate;

AllowlistModule public allowlistModule;
TimeRangeModule public timeRangeModule;
Expand All @@ -49,8 +51,9 @@ abstract contract ModularAccountBenchmarkBase is BenchmarkBase, ModuleSignatureU
constructor(string memory accountImplName) BenchmarkBase(accountImplName) {
(sessionSigner1, sessionSigner1Key) = makeAddrAndKey("session1");

accountImpl = _deployModularAccount(IEntryPoint(entryPoint));
semiModularImpl = _deploySemiModularAccountBytecode(IEntryPoint(entryPoint));
executionInstallDelegate = new ExecutionInstallDelegate();
accountImpl = _deployModularAccount(IEntryPoint(entryPoint), executionInstallDelegate);
semiModularImpl = _deploySemiModularAccountBytecode(IEntryPoint(entryPoint), executionInstallDelegate);
singleSignerValidationModule = _deploySingleSignerValidationModule();

factory = new AccountFactory(
Expand Down
4 changes: 2 additions & 2 deletions src/account/AccountBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ abstract contract AccountBase is IAccount {

error NotEntryPoint();

constructor(IEntryPoint anEntryPoint) {
_ENTRY_POINT = anEntryPoint;
constructor(IEntryPoint _entryPoint) {
_ENTRY_POINT = _entryPoint;
}

/// @inheritdoc IAccount
Expand Down
5 changes: 4 additions & 1 deletion src/account/ModularAccount.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import {
} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {ModularAccountBase} from "./ModularAccountBase.sol";

/// @title Modular Account
/// @author Alchemy
/// @notice This contract allows initializing with a validation config (of a validation module) to be installed on
/// the account.
contract ModularAccount is ModularAccountBase {
constructor(IEntryPoint anEntryPoint) ModularAccountBase(anEntryPoint) {}
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
ModularAccountBase(entryPoint, executionInstallDelegate)
{}

/// @notice Initializes the account with a validation function added to the global pool.
/// @dev This function is only callable once.
Expand Down
6 changes: 4 additions & 2 deletions src/account/ModularAccountBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,12 @@ abstract contract ModularAccountBase is
ExecutionLib.doCachedPostHooks(postHookData);
}

constructor(IEntryPoint anEntryPoint) AccountBase(anEntryPoint) {
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
AccountBase(entryPoint)
{
_disableInitializers();

_EXECUTION_INSTALL_DELEGATE = address(new ExecutionInstallDelegate());
_EXECUTION_INSTALL_DELEGATE = address(executionInstallDelegate);
}

// EXTERNAL FUNCTIONS
Expand Down
5 changes: 4 additions & 1 deletion src/account/SemiModularAccount7702.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.26;
import {IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";

/// @title Semi-Modular Account for EIP-7702 EOAs
Expand All @@ -14,7 +15,9 @@ import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";
contract SemiModularAccount7702 is SemiModularAccountBase {
error UpgradeNotAllowed();

constructor(IEntryPoint anEntryPoint) SemiModularAccountBase(anEntryPoint) {}
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
SemiModularAccountBase(entryPoint, executionInstallDelegate)
{}

/// @inheritdoc IModularAccount
function accountId() external pure override returns (string memory) {
Expand Down
6 changes: 5 additions & 1 deletion src/account/SemiModularAccountBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/Messa
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

import {FALLBACK_VALIDATION} from "../helpers/Constants.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SignatureType} from "../helpers/SignatureType.sol";
import {RTCallBuffer, SigCallBuffer, UOCallBuffer} from "../libraries/ExecutionLib.sol";
import {ModularAccountBase} from "./ModularAccountBase.sol";
Expand Down Expand Up @@ -46,7 +48,9 @@ abstract contract SemiModularAccountBase is ModularAccountBase {
error FallbackSignerDisabled();
error InvalidSignatureType();

constructor(IEntryPoint anEntryPoint) ModularAccountBase(anEntryPoint) {}
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
ModularAccountBase(entryPoint, executionInstallDelegate)
{}

/// @notice Updates the fallback signer data in storage.
/// @param fallbackSigner The new signer to set.
Expand Down
5 changes: 4 additions & 1 deletion src/account/SemiModularAccountBytecode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {IModularAccount} from "@erc6900/reference-implementation/interfaces/IMod
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";
import {LibClone} from "solady/utils/LibClone.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";

/// @title Semi-Modular Account Bytecode
Expand All @@ -14,7 +15,9 @@ import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";
/// @dev Inherits SemiModularAccountBase. This account requires that its proxy is compliant with Solady's LibClone
/// ERC1967WithImmutableArgs bytecode with a bytecode-appended address to be used as the fallback signer.
contract SemiModularAccountBytecode is SemiModularAccountBase {
constructor(IEntryPoint anEntryPoint) SemiModularAccountBase(anEntryPoint) {}
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
SemiModularAccountBase(entryPoint, executionInstallDelegate)
{}

/// @inheritdoc IModularAccount
function accountId() external pure override returns (string memory) {
Expand Down
5 changes: 4 additions & 1 deletion src/account/SemiModularAccountStorageOnly.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.26;
import {IModularAccount} from "@erc6900/reference-implementation/interfaces/IModularAccount.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

import {ExecutionInstallDelegate} from "../helpers/ExecutionInstallDelegate.sol";
import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";

/// @title Semi-Modular Account Storage Only
Expand All @@ -14,7 +15,9 @@ import {SemiModularAccountBase} from "./SemiModularAccountBase.sol";
/// `upgradeToAndCall()`. Use the `SemiModularAccountBytecode` instead for new accounts, this implementation should
/// only be used for account upgrades.
contract SemiModularAccountStorageOnly is SemiModularAccountBase {
constructor(IEntryPoint anEntryPoint) SemiModularAccountBase(anEntryPoint) {}
constructor(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
SemiModularAccountBase(entryPoint, executionInstallDelegate)
{}

function initialize(address initialSigner) external initializer {
SemiModularAccountStorage storage smaStorage = _getSemiModularAccountStorage();
Expand Down
10 changes: 5 additions & 5 deletions test/account/ModularAccount.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ contract ModularAccountTest is AccountTestBase {

function test_upgradeToAndCall() public withSMATest {
vm.startPrank(address(entryPoint));
ModularAccount account3 = new ModularAccount(entryPoint);
ModularAccount account3 = new ModularAccount(entryPoint, executionInstallDelegate);
bytes32 slot = account3.proxiableUUID();

// account has impl from factory
Expand Down Expand Up @@ -559,12 +559,12 @@ contract ModularAccountTest is AccountTestBase {
vm.stopPrank();
}

function test_performCreate() public withSMATest {
function test_performCreate_create() public withSMATest {
address expectedAddr = vm.computeCreateAddress(address(account1), vm.getNonce(address(account1)));
vm.prank(address(entryPoint));
address returnedAddr = account1.performCreate(
0,
abi.encodePacked(type(ModularAccount).creationCode, abi.encode(address(entryPoint))),
abi.encodePacked(type(ModularAccount).creationCode, abi.encode(entryPoint, executionInstallDelegate)),
false,
bytes32(0)
);
Expand All @@ -578,9 +578,9 @@ contract ModularAccountTest is AccountTestBase {
account1.performCreate(0, abi.encodePacked(type(MockRevertingConstructor).creationCode), false, 0);
}

function test_performCreate2() public withSMATest {
function test_performCreate_create2() public withSMATest {
bytes memory initCode =
abi.encodePacked(type(ModularAccount).creationCode, abi.encode(address(entryPoint)));
abi.encodePacked(type(ModularAccount).creationCode, abi.encode(entryPoint, executionInstallDelegate));
bytes32 initCodeHash = keccak256(initCode);
bytes32 salt = bytes32(hex"01234b");

Expand Down
2 changes: 1 addition & 1 deletion test/account/UpgradeToSma.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ contract UpgradeToSmaTest is AccountTestBase {

function setUp() public override {
_revertSnapshot = vm.snapshotState();
smaStorageImpl = address(new SemiModularAccountStorageOnly(entryPoint));
smaStorageImpl = address(new SemiModularAccountStorageOnly(entryPoint, executionInstallDelegate));
(owner2, owner2Key) = makeAddrAndKey("owner2");
transferAmount = 0.1 ether;
}
Expand Down
11 changes: 8 additions & 3 deletions test/utils/AccountTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {ModularAccount} from "../../src/account/ModularAccount.sol";
import {SemiModularAccountBytecode} from "../../src/account/SemiModularAccountBytecode.sol";
import {AccountFactory} from "../../src/factory/AccountFactory.sol";
import {FALLBACK_VALIDATION} from "../../src/helpers/Constants.sol";
import {ExecutionInstallDelegate} from "../../src/helpers/ExecutionInstallDelegate.sol";
import {SingleSignerValidationModule} from "../../src/modules/validation/SingleSignerValidationModule.sol";
import {WebAuthnValidationModule} from "../../src/modules/validation/WebAuthnValidationModule.sol";

Expand All @@ -55,6 +56,7 @@ abstract contract AccountTestBase is OptimizedTest, ModuleSignatureUtils {
SingleSignerValidationModule public singleSignerValidationModule;
ModularAccount public accountImplementation;
SemiModularAccountBytecode public semiModularAccountImplementation;
ExecutionInstallDelegate public executionInstallDelegate;
AccountFactory public factory;

address public factoryOwner;
Expand Down Expand Up @@ -104,10 +106,13 @@ abstract contract AccountTestBase is OptimizedTest, ModuleSignatureUtils {
singleSignerValidationModule = _deploySingleSignerValidationModule();
// vm.etch(address(0), deployedSingleSignerValidationModule.code);

accountImplementation = _deployModularAccount(entryPoint);
executionInstallDelegate = _deployExecutionInstallDelegate();

semiModularAccountImplementation =
SemiModularAccountBytecode(payable(_deploySemiModularAccountBytecode(entryPoint)));
accountImplementation = _deployModularAccount(entryPoint, executionInstallDelegate);

semiModularAccountImplementation = SemiModularAccountBytecode(
payable(_deploySemiModularAccountBytecode(entryPoint, executionInstallDelegate))
);

address webAuthnModule = address(new WebAuthnValidationModule());

Expand Down
36 changes: 27 additions & 9 deletions test/utils/OptimizedTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntry

import {ModularAccount} from "../../src/account/ModularAccount.sol";
import {SemiModularAccountBytecode} from "../../src/account/SemiModularAccountBytecode.sol";

import {ExecutionInstallDelegate} from "../../src/helpers/ExecutionInstallDelegate.sol";
import {SingleSignerValidationModule} from "../../src/modules/validation/SingleSignerValidationModule.sol";

/// @dev This contract provides functions to deploy optimized (via IR) precompiled contracts. By compiling just
Expand All @@ -45,28 +47,36 @@ abstract contract OptimizedTest is Test {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
}

function _deployModularAccount(IEntryPoint entryPoint) internal returns (ModularAccount) {
function _deployModularAccount(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
internal
returns (ModularAccount)
{
return _isOptimizedTest()
? ModularAccount(
payable(deployCode("out-optimized/ModularAccount.sol/ModularAccount.json", abi.encode(entryPoint)))
payable(
deployCode(
"out-optimized/ModularAccount.sol/ModularAccount.json",
abi.encode(entryPoint, executionInstallDelegate)
)
)
)
: new ModularAccount(entryPoint);
: new ModularAccount(entryPoint, executionInstallDelegate);
}

function _deploySemiModularAccountBytecode(IEntryPoint entryPoint)
internal
returns (SemiModularAccountBytecode)
{
function _deploySemiModularAccountBytecode(
IEntryPoint entryPoint,
ExecutionInstallDelegate executionInstallDelegate
) internal returns (SemiModularAccountBytecode) {
return _isOptimizedTest()
? SemiModularAccountBytecode(
payable(
deployCode(
"out-optimized/SemiModularAccountBytecode.sol/SemiModularAccountBytecode.json",
abi.encode(entryPoint)
abi.encode(entryPoint, executionInstallDelegate)
)
)
)
: new SemiModularAccountBytecode(entryPoint);
: new SemiModularAccountBytecode(entryPoint, executionInstallDelegate);
}

function _deploySingleSignerValidationModule() internal returns (SingleSignerValidationModule) {
Expand All @@ -77,6 +87,14 @@ abstract contract OptimizedTest is Test {
: new SingleSignerValidationModule();
}

function _deployExecutionInstallDelegate() internal returns (ExecutionInstallDelegate) {
return _isOptimizedTest()
? ExecutionInstallDelegate(
deployCode("out-optimized/ExecutionInstallDelegate.sol/ExecutionInstallDelegate.json")
)
: new ExecutionInstallDelegate();
}

function _deployEntryPoint070() internal returns (EntryPoint) {
address deployedEntryPointAddr = 0x0000000071727De22E5E9d8BAf0edAc6f37da032;
address deployedSenderCreatorAddr = 0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C;
Expand Down

0 comments on commit 005856d

Please sign in to comment.