diff --git a/script/DeployFactory.s.sol b/script/DeployFactory.s.sol new file mode 100644 index 00000000..880f6b58 --- /dev/null +++ b/script/DeployFactory.s.sol @@ -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 = _getModularAccountImpl(); + semiModularAccountBytecodeImpl = _getSemiModularAccountBytecodeImpl(); + singleSignerValidationModule = _getSingleSignerValidationModule(); + webAuthnValidationModule = _getWebAuthnValidationModule(); + factoryOwner = _getFactoryOwner(); + + // Load the expected address and salt from env vars. + expectedFactoryAddr = vm.envOr("FACTORY", address(0)); + factorySalt = vm.envOr("FACTORY_SALT", uint256(0)); + } + + function run() public onlyProfile("optimized-build") { + console.log("******** Deploying Modules *********"); + + vm.startBroadcast(); + + _safeDeploy( + "Account Factory", + expectedFactoryAddr, + factorySalt, + _getAccountFactoryInitcode( + entryPoint, + modularAccountImpl, + semiModularAccountBytecodeImpl, + singleSignerValidationModule, + webAuthnValidationModule, + factoryOwner + ), + _deployFactory + ); + + vm.stopBroadcast(); + + console.log("******** Factory Deployed *********"); + } + + // Wrapper function to be called within _safeDeploy using the context in this contract. + function _deployFactory(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"); + } + } +} diff --git a/script/GetInitcodeHash.s.sol b/script/GetInitcodeHash.s.sol index f2fa5caa..90a6b3d9 100644 --- a/script/GetInitcodeHash.s.sol +++ b/script/GetInitcodeHash.s.sol @@ -47,16 +47,8 @@ contract GetInitcodeHashScript is ScriptBase, Artifacts { console.log("- WebAuthnValidationModule: %x", uint256(keccak256(_getWebAuthnValidationModuleInitcode()))); console.log("Artifact initcode hashes with dependencies on EntryPoint and ExecutionInstallDelegate:"); - IEntryPoint entryPoint = IEntryPoint(payable(vm.envOr("ENTRYPOINT", address(0)))); - if (address(entryPoint) == address(0)) { - console.log( - "Env Variable 'ENTRYPOINT' not found or invalid, defaulting to v0.7 EntryPoint at " - "0x0000000071727De22E5E9d8BAf0edAc6f37da032" - ); - entryPoint = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032); - } else { - console.log("Using user-defined EntryPoint at: %x", address(entryPoint)); - } + IEntryPoint entryPoint = _getEntryPoint(); //IEntryPoint(payable(vm.envOr("ENTRYPOINT", address(0)))); + ExecutionInstallDelegate executionInstallDelegate = ExecutionInstallDelegate(vm.envOr("EXECUTION_INSTALL_DELEGATE", address(0))); @@ -93,12 +85,11 @@ contract GetInitcodeHashScript is ScriptBase, Artifacts { "WebAuthnValidationModule, and owner address:" ); - ModularAccount modularAccountImpl = ModularAccount(payable(vm.envOr("MODULAR_ACCOUNT_IMPL", address(0)))); - SemiModularAccountBytecode semiModularImpl = - SemiModularAccountBytecode(payable(vm.envOr("SEMI_MODULAR_ACCOUNT_BYTECODE_IMPL", address(0)))); - address singleSignerValidationModule = vm.envOr("SINGLE_SIGNER_VALIDATION_MODULE", address(0)); - address webAuthnValidationModule = vm.envOr("WEBAUTHN_VALIDATION_MODULE", address(0)); - address factoryOwner = vm.envOr("FACTORY_OWNER", address(0)); + ModularAccount modularAccountImpl = _getModularAccountImpl(); + SemiModularAccountBytecode semiModularImpl = _getSemiModularAccountBytecodeImpl(); + address singleSignerValidationModule = _getSingleSignerValidationModule(); + address webAuthnValidationModule = _getWebAuthnValidationModule(); + address factoryOwner = _getFactoryOwner(); if (address(modularAccountImpl) == address(0)) { console.log( diff --git a/script/ScriptBase.sol b/script/ScriptBase.sol index 570d0b67..d6c57b09 100644 --- a/script/ScriptBase.sol +++ b/script/ScriptBase.sol @@ -4,6 +4,9 @@ pragma solidity ^0.8.26; import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; +import {ModularAccount} from "../src/account/ModularAccount.sol"; +import {SemiModularAccountBytecode} from "../src/account/SemiModularAccountBytecode.sol"; +import {IEntryPoint} from "@eth-infinitism/account-abstraction/interfaces/IEntryPoint.sol"; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; abstract contract ScriptBase is Script { @@ -17,6 +20,41 @@ abstract contract ScriptBase is Script { _; } + function _getEntryPoint() internal view returns (IEntryPoint) { + IEntryPoint entryPoint = IEntryPoint(payable(vm.envOr("ENTRYPOINT", address(0)))); + if (address(entryPoint) == address(0)) { + console.log( + "Env Variable 'ENTRYPOINT' not found or invalid, defaulting to v0.7 EntryPoint at " + "0x0000000071727De22E5E9d8BAf0edAc6f37da032" + ); + entryPoint = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032); + } else { + console.log("Using user-defined EntryPoint at: %x", address(entryPoint)); + } + + return entryPoint; + } + + function _getModularAccountImpl() internal view returns (ModularAccount) { + return ModularAccount(payable(vm.envOr("MODULAR_ACCOUNT_IMPL", address(0)))); + } + + function _getSemiModularAccountBytecodeImpl() internal view returns (SemiModularAccountBytecode) { + return SemiModularAccountBytecode(payable(vm.envOr("SEMI_MODULAR_ACCOUNT_BYTECODE_IMPL", address(0)))); + } + + function _getSingleSignerValidationModule() internal view returns (address) { + return vm.envOr("SINGLE_SIGNER_VALIDATION_MODULE", address(0)); + } + + function _getWebAuthnValidationModule() internal view returns (address) { + return vm.envOr("WEBAUTHN_VALIDATION_MODULE", address(0)); + } + + function _getFactoryOwner() internal view returns (address) { + return vm.envOr("FACTORY_OWNER", address(0)); + } + function _safeDeploy( string memory contractName, address expectedAddress,