Skip to content
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

feat: deploy and address prediction scripts #321

Merged
merged 7 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"fmt:check": "forge fmt --check && FOUNDRY_PROFILE=gas forge fmt --check",
"gas": "FOUNDRY_PROFILE=gas forge test -vv",
"gas:check": "FOUNDRY_PROFILE=gas FORGE_SNAPSHOT_CHECK=true forge test -vv",
"initcodehashes": "FOUNDRY_PROFILE=optimized-build forge script GetInitcodeHashScript",
"lcov": "forge coverage --no-match-coverage '(test)' --nmt '(testFuzz|invariant)' --report lcov",
"lint": "pnpm lint:src && pnpm lint:test && pnpm lint:gas && pnpm lint:script",
"lint:src": "solhint --max-warnings 0 -c ./config/solhint-src.json './src/**/*.sol'",
Expand Down
57 changes: 34 additions & 23 deletions script/Artifacts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,33 @@ abstract contract Artifacts {
address singleSignerValidationModule,
address webAuthnValidationModule,
address owner
) internal returns (AccountFactory) {
return new AccountFactory{salt: salt}(
entryPoint, accountImpl, semiModularImpl, singleSignerValidationModule, webAuthnValidationModule, owner
) internal returns (address) {
return address(
new AccountFactory{salt: salt}(
entryPoint,
accountImpl,
semiModularImpl,
singleSignerValidationModule,
webAuthnValidationModule,
owner
)
);
}

function _getAllowlistModuleInitcode() internal pure returns (bytes memory) {
return type(AllowlistModule).creationCode;
}

function _deployAllowlistModule(bytes32 salt) internal returns (AllowlistModule) {
return new AllowlistModule{salt: salt}();
function _deployAllowlistModule(bytes32 salt) internal returns (address) {
return address(new AllowlistModule{salt: salt}());
}

function _getExecutionInstallDelegateInitcode() internal pure returns (bytes memory) {
return type(ExecutionInstallDelegate).creationCode;
}

function _deployExecutionInstallDelegate(bytes32 salt) internal returns (ExecutionInstallDelegate) {
return new ExecutionInstallDelegate{salt: salt}();
function _deployExecutionInstallDelegate(bytes32 salt) internal returns (address) {
return address(new ExecutionInstallDelegate{salt: salt}());
}

function _getModularAccountInitcode(IEntryPoint entryPoint, ExecutionInstallDelegate executionInstallDelegate)
Expand All @@ -93,24 +100,24 @@ abstract contract Artifacts {
bytes32 salt,
IEntryPoint entryPoint,
ExecutionInstallDelegate executionInstallDelegate
) internal returns (ModularAccount) {
return new ModularAccount{salt: salt}(entryPoint, executionInstallDelegate);
) internal returns (address) {
return address(new ModularAccount{salt: salt}(entryPoint, executionInstallDelegate));
}

function _getNativeTokenLimitModuleInitcode() internal pure returns (bytes memory) {
return type(NativeTokenLimitModule).creationCode;
}

function _deployNativeTokenLimitModule(bytes32 salt) internal returns (NativeTokenLimitModule) {
return new NativeTokenLimitModule{salt: salt}();
function _deployNativeTokenLimitModule(bytes32 salt) internal returns (address) {
return address(new NativeTokenLimitModule{salt: salt}());
}

function _getPaymasterGuardModuleInitcode() internal pure returns (bytes memory) {
return type(PaymasterGuardModule).creationCode;
}

function _deployPaymasterGuardModule(bytes32 salt) internal returns (PaymasterGuardModule) {
return new PaymasterGuardModule{salt: salt}();
function _deployPaymasterGuardModule(bytes32 salt) internal returns (address) {
return address(new PaymasterGuardModule{salt: salt}());
}

function _getSemiModularAccount7702Initcode(
Expand All @@ -126,8 +133,8 @@ abstract contract Artifacts {
bytes32 salt,
IEntryPoint entryPoint,
ExecutionInstallDelegate executionInstallDelegate
) internal returns (SemiModularAccount7702) {
return new SemiModularAccount7702{salt: salt}(entryPoint, executionInstallDelegate);
) internal returns (address) {
return address(new SemiModularAccount7702{salt: salt}(entryPoint, executionInstallDelegate));
}

function _getSemiModularAccountBytecodeInitcode(
Expand All @@ -143,8 +150,8 @@ abstract contract Artifacts {
bytes32 salt,
IEntryPoint entryPoint,
ExecutionInstallDelegate executionInstallDelegate
) internal returns (SemiModularAccountBytecode) {
return new SemiModularAccountBytecode{salt: salt}(entryPoint, executionInstallDelegate);
) internal returns (address) {
return address(new SemiModularAccountBytecode{salt: salt}(entryPoint, executionInstallDelegate));
}

function _getSemiModularAccountStorageOnlyInitcode(
Expand All @@ -160,27 +167,31 @@ abstract contract Artifacts {
bytes32 salt,
IEntryPoint entryPoint,
ExecutionInstallDelegate executionInstallDelegate
) internal returns (SemiModularAccountStorageOnly) {
return new SemiModularAccountStorageOnly{salt: salt}(entryPoint, executionInstallDelegate);
) internal returns (address) {
return address(new SemiModularAccountStorageOnly{salt: salt}(entryPoint, executionInstallDelegate));
}

function _getSingleSignerValidationModuleInitcode() internal pure returns (bytes memory) {
return type(SingleSignerValidationModule).creationCode;
}

function _deploySingleSignerValidationModule(bytes32 salt) internal returns (SingleSignerValidationModule) {
return new SingleSignerValidationModule{salt: salt}();
function _deploySingleSignerValidationModule(bytes32 salt) internal returns (address) {
return address(new SingleSignerValidationModule{salt: salt}());
}

function _getTimeRangeModuleInitcode() internal pure returns (bytes memory) {
return type(TimeRangeModule).creationCode;
}

function _deployTimeRangeModule(bytes32 salt) internal returns (TimeRangeModule) {
return new TimeRangeModule{salt: salt}();
function _deployTimeRangeModule(bytes32 salt) internal returns (address) {
return address(new TimeRangeModule{salt: salt}());
}

function _getWebAuthnValidationModuleInitcode() internal pure returns (bytes memory) {
return type(WebAuthnValidationModule).creationCode;
}

function _deployWebAuthnValidationModule(bytes32 salt) internal returns (address) {
return address(new WebAuthnValidationModule{salt: salt}());
}
}
115 changes: 115 additions & 0 deletions script/DeployAccounts.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import {console} from "forge-std/console.sol";

import {ExecutionInstallDelegate} from "../src/helpers/ExecutionInstallDelegate.sol";
import {Artifacts} from "./Artifacts.sol";
import {ScriptBase} from "./ScriptBase.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

// Deploys the three account implementations and an execution install delegate. This requires the following env
// vars to be set:
// - ENTRY_POINT (optional)
contract DeployAccountsScript is ScriptBase, Artifacts {
// State vars for expected addresses and salts.

IEntryPoint public entryPoint;

address public expectedExecutionInstallDelegate;
uint256 public executionInstallDelegateSalt;

address public expectedModularAccountImpl;
uint256 public modularAccountImplSalt;

address public expectedSemiModularAccountBytecodeImpl;
uint256 public semiModularAccountBytecodeImplSalt;

address public expectedSemiModularAccountStorageOnlyImpl;
uint256 public semiModularAccountStorageOnlyImplSalt;

function setUp() public {
// Load the required addresses for the deployment from env vars.
entryPoint = _getEntryPoint();

expectedExecutionInstallDelegate = _getExecutionInstallDelegate();
executionInstallDelegateSalt = _getSaltOrZero("EXECUTION_INSTALL_DELEGATE");

expectedModularAccountImpl = _getModularAccountImpl();
modularAccountImplSalt = _getSaltOrZero("MODULAR_ACCOUNT_IMPL");

expectedSemiModularAccountBytecodeImpl = _getSemiModularAccountBytecodeImpl();
semiModularAccountBytecodeImplSalt = _getSaltOrZero("SEMI_MODULAR_ACCOUNT_BYTECODE_IMPL");

expectedSemiModularAccountStorageOnlyImpl = address(_getSemiModularAccountStorageOnlyImpl());
semiModularAccountStorageOnlyImplSalt = _getSaltOrZero("SEMI_MODULAR_ACCOUNT_STORAGE_ONLY_IMPL");
}

function run() public onlyProfile("optimized-build") {
console.log("******** Deploying Account Implementations and Execution Install Delegate *********");

vm.startBroadcast();

_safeDeploy(
"Execution Install Delegate",
expectedExecutionInstallDelegate,
executionInstallDelegateSalt,
_getExecutionInstallDelegateInitcode(),
_deployExecutionInstallDelegate
);

// At this point, the delegate and entrypoint are valid, so we can safely proceed with
// using them as parameters and accessing them in wrapped functions.

_safeDeploy(
"Modular Account Impl",
expectedModularAccountImpl,
modularAccountImplSalt,
_getModularAccountInitcode(entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate)),
_wrappedDeployModularAccount
);

_safeDeploy(
"Semi Modular Account Bytecode Impl",
expectedSemiModularAccountBytecodeImpl,
semiModularAccountBytecodeImplSalt,
_getSemiModularAccountBytecodeInitcode(
entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate)
),
_wrappedDeploySemiModularAccountBytecode
);

_safeDeploy(
"Semi Modular Account Storage Only Impl",
expectedSemiModularAccountStorageOnlyImpl,
semiModularAccountStorageOnlyImplSalt,
_getSemiModularAccountStorageOnlyInitcode(
entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate)
),
_wrappedDeploySemiModularAccountStorageOnly
);

vm.stopBroadcast();

console.log("******** Account Implementations and Execution Install Delegate Deployed *********");
}

// These functions wrap the internal deployment functions to provide access to the needed state variables
// without affecting the expected signature from _safeDeploy.

function _wrappedDeployModularAccount(bytes32 salt) internal returns (address) {
return _deployModularAccount(salt, entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate));
}

function _wrappedDeploySemiModularAccountBytecode(bytes32 salt) internal returns (address) {
return _deploySemiModularAccountBytecode(
salt, entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate)
);
}

function _wrappedDeploySemiModularAccountStorageOnly(bytes32 salt) internal returns (address) {
return _deploySemiModularAccountStorageOnly(
salt, entryPoint, ExecutionInstallDelegate(expectedExecutionInstallDelegate)
);
}
}
134 changes: 134 additions & 0 deletions script/DeployFactory.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import {console} from "forge-std/console.sol";

import {ModularAccount} from "../src/account/ModularAccount.sol";
import {SemiModularAccountBytecode} from "../src/account/SemiModularAccountBytecode.sol";
import {Artifacts} from "./Artifacts.sol";
import {ScriptBase} from "./ScriptBase.sol";
import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol";

// Deploys the Account Factory. This requires the following env vars to be set:
// - ENTRY_POINT
// - MODULAR_ACCOUNT_IMPL
// - SEMI_MODULAR_ACCOUNT_BYTECODE_IMPL
// - SINGLE_SIGNER_VALIDATION_MODULE
// - WEBAUTHN_VALIDATION_MODULE
// - FACTORY_OWNER
contract DeployFactoryScript is ScriptBase, Artifacts {
// State vars for expected addresses and salts.

address public expectedFactoryAddr;
uint256 public factorySalt;

// State vars for factory dependencies

IEntryPoint public entryPoint;
ModularAccount public modularAccountImpl;
SemiModularAccountBytecode public semiModularAccountBytecodeImpl;
address public singleSignerValidationModule;
address public webAuthnValidationModule;
address public factoryOwner;

function setUp() public {
// Load the required addresses for the factory deployment from env vars.
entryPoint = _getEntryPoint();
modularAccountImpl = ModularAccount(payable(_getModularAccountImpl()));
semiModularAccountBytecodeImpl = SemiModularAccountBytecode(payable(_getSemiModularAccountBytecodeImpl()));
singleSignerValidationModule = _getSingleSignerValidationModule();
webAuthnValidationModule = _getWebAuthnValidationModule();
factoryOwner = _getFactoryOwner();

// Load the expected address and salt from env vars.
expectedFactoryAddr = vm.envOr("ACCOUNT_FACTORY", address(0));
factorySalt = _getSaltOrZero("ACCOUNT_FACTORY");
}

function run() public onlyProfile("optimized-build") {
console.log("******** Deploying Factory *********");

vm.startBroadcast();

_safeDeploy(
"Account Factory",
expectedFactoryAddr,
factorySalt,
_getAccountFactoryInitcode(
entryPoint,
modularAccountImpl,
semiModularAccountBytecodeImpl,
singleSignerValidationModule,
webAuthnValidationModule,
factoryOwner
),
_wrappedDeployAccountFactory
);

vm.stopBroadcast();

console.log("******** Factory Deployed *********");
}

// Wrapper function to be called within _safeDeploy using the context in this contract.
function _wrappedDeployAccountFactory(bytes32 salt) internal returns (address) {
_ensureNonzeroFactoryArgs();
return _deployAccountFactory(
salt,
entryPoint,
modularAccountImpl,
semiModularAccountBytecodeImpl,
singleSignerValidationModule,
webAuthnValidationModule,
factoryOwner
);
}

function _ensureNonzeroFactoryArgs() internal view {
bool shouldRevert;
if (address(modularAccountImpl) == address(0)) {
console.log("Env Variable 'MODULAR_ACCOUNT_IMPL' not found or invalid during factory deployment");
shouldRevert = true;
} else {
console.log("Using user-defined ModularAccount at: %x", address(modularAccountImpl));
}

if (address(semiModularAccountBytecodeImpl) == address(0)) {
console.log(
"Env Variable 'SEMI_MODULAR_ACCOUNT_BYTECODE_IMPL' not found or invalid during factory deployment"
);
shouldRevert = true;
} else {
console.log(
"Using user-defined SemiModularAccountBytecode at: %x", address(semiModularAccountBytecodeImpl)
);
}

if (singleSignerValidationModule == address(0)) {
console.log(
"Env Variable 'SINGLE_SIGNER_VALIDATION_MODULE' not found or invalid during factory deployment"
);
shouldRevert = true;
} else {
console.log("Using user-defined SingleSignerValidationModule at: %x", singleSignerValidationModule);
}

if (webAuthnValidationModule == address(0)) {
console.log("Env Variable 'WEBAUTHN_VALIDATION_MODULE' not found or invalid during factory deployment");
shouldRevert = true;
} else {
console.log("Using user-defined WebAuthnValidationModule at: %x", webAuthnValidationModule);
}

if (factoryOwner == address(0)) {
console.log("Env Variable 'FACTORY_OWNER' not found or invalid during factory deployment");
shouldRevert = true;
} else {
console.log("Using user-defined factory owner at: %x", factoryOwner);
}

if (shouldRevert) {
revert("Missing or invalid env variables during factory deployment");
}
}
}
Loading
Loading