Skip to content

Commit

Permalink
chore: use immutable single signer validation
Browse files Browse the repository at this point in the history
  • Loading branch information
howydev committed Jul 19, 2024
1 parent 4b9b766 commit b2e06d0
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 26 deletions.
37 changes: 15 additions & 22 deletions src/account/AccountFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

import {UpgradeableModularAccount} from "../account/UpgradeableModularAccount.sol";
import {ValidationConfigLib} from "../helpers/ValidationConfigLib.sol";
import {SingleSignerValidation} from "../plugins/validation/SingleSignerValidation.sol";

contract AccountFactory is Ownable {
UpgradeableModularAccount public accountImplementation;
bytes32 private immutable _PROXY_BYTECODE_HASH;
uint32 public constant UNSTAKE_DELAY = 1 weeks;
IEntryPoint public immutable ENTRY_POINT;
address public immutable SINGLE_SIGNER_VALIDATION;

constructor(IEntryPoint _entryPoint, UpgradeableModularAccount _accountImpl) Ownable(msg.sender) {
constructor(IEntryPoint _entryPoint, UpgradeableModularAccount _accountImpl, address _singleSignerValidation)
Ownable(msg.sender)
{
ENTRY_POINT = _entryPoint;
_PROXY_BYTECODE_HASH =
keccak256(abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(address(_accountImpl), "")));
accountImplementation = _accountImpl;
SINGLE_SIGNER_VALIDATION = _singleSignerValidation;
}

/**
Expand All @@ -31,13 +34,11 @@ contract AccountFactory is Ownable {
* This method returns an existing account address so that entryPoint.getSenderAddress() would work even after
* account creation
*/
function createAccount(
address owner,
uint256 salt,
uint32 entityId,
SingleSignerValidation singleSignerValidation
) external returns (UpgradeableModularAccount) {
bytes32 combinedSalt = getSalt(owner, salt, entityId, address(singleSignerValidation));
function createAccount(address owner, uint256 salt, uint32 entityId)
external
returns (UpgradeableModularAccount)
{
bytes32 combinedSalt = getSalt(owner, salt, entityId);
address addr = Create2.computeAddress(combinedSalt, _PROXY_BYTECODE_HASH);

// short circuit if exists
Expand All @@ -47,7 +48,7 @@ contract AccountFactory is Ownable {
new ERC1967Proxy{salt: combinedSalt}(address(accountImplementation), "");
// point proxy to actual implementation and init plugins
UpgradeableModularAccount(payable(addr)).initializeWithValidation(
ValidationConfigLib.pack(address(singleSignerValidation), entityId, true, true),
ValidationConfigLib.pack(SINGLE_SIGNER_VALIDATION, entityId, true, true),
new bytes4[](0),
pluginInstallData,
"",
Expand All @@ -73,19 +74,11 @@ contract AccountFactory is Ownable {
/**
* Calculate the counterfactual address of this account as it would be returned by createAccount()
*/
function getAddress(address owner, uint256 salt, uint32 entityId, address validation)
external
view
returns (address)
{
return Create2.computeAddress(getSalt(owner, salt, entityId, validation), _PROXY_BYTECODE_HASH);
function getAddress(address owner, uint256 salt, uint32 entityId) external view returns (address) {
return Create2.computeAddress(getSalt(owner, salt, entityId), _PROXY_BYTECODE_HASH);
}

function getSalt(address owner, uint256 salt, uint32 entityId, address validation)
public
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(owner, salt, entityId, validation));
function getSalt(address owner, uint256 salt, uint32 entityId) public pure returns (bytes32) {
return keccak256(abi.encodePacked(owner, salt, entityId));
}
}
8 changes: 4 additions & 4 deletions test/account/AccountFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ contract AccountFactoryTest is AccountTestBase {

function setUp() public {
_account = new UpgradeableModularAccount(entryPoint);
_factory = new AccountFactory(entryPoint, _account);
_factory = new AccountFactory(entryPoint, _account, address(singleSignerValidation));
}

function test_createAccount() public {
UpgradeableModularAccount account = _factory.createAccount(address(this), 100, 0, singleSignerValidation);
UpgradeableModularAccount account = _factory.createAccount(address(this), 100, 0);

assertEq(address(account.entryPoint()), address(entryPoint));
}

function test_multipleDeploy() public {
UpgradeableModularAccount account = _factory.createAccount(address(this), 100, 0, singleSignerValidation);
UpgradeableModularAccount account = _factory.createAccount(address(this), 100, 0);

uint256 startGas = gasleft();

UpgradeableModularAccount account2 = _factory.createAccount(address(this), 100, 0, singleSignerValidation);
UpgradeableModularAccount account2 = _factory.createAccount(address(this), 100, 0);

// Assert that the 2nd deployment call cost less than 1 sstore
// Implies that no deployment was done on the second calls
Expand Down

0 comments on commit b2e06d0

Please sign in to comment.