// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.23; import {AereThresholdAccount} from "./AereThresholdAccount.sol"; /// @title AereThresholdAccountFactory /// @notice Deterministic (CREATE2) factory for non-custodial post-quantum threshold accounts. /// The account address is a pure function of (entryPoint, scheme, threshold, pubKeys, /// salt), so it can be counterfactually funded before deployment. Permissionless; the /// factory holds no authority over any account it deploys. contract AereThresholdAccountFactory { event AccountCreated(address indexed account, uint8 scheme, uint8 threshold, uint8 size, bytes32 salt); /// @notice Deploy (or return the existing) threshold account for the given committee + salt. function createAccount( address entryPoint, uint8 scheme, uint8 threshold, bytes[] calldata pubKeys, bytes32 salt ) external returns (address account) { bytes32 create2Salt = _salt(entryPoint, scheme, threshold, pubKeys, salt); address predicted = _addressFor(create2Salt); if (predicted.code.length > 0) { return predicted; // idempotent } AereThresholdAccount acc = new AereThresholdAccount{salt: create2Salt}(); acc.initialize(entryPoint, scheme, threshold, pubKeys); account = address(acc); require(account == predicted, "addr mismatch"); emit AccountCreated(account, scheme, threshold, uint8(pubKeys.length), salt); } /// @notice The counterfactual address of the account for the given committee + salt. function computeAddress( address entryPoint, uint8 scheme, uint8 threshold, bytes[] calldata pubKeys, bytes32 salt ) external view returns (address) { return _addressFor(_salt(entryPoint, scheme, threshold, pubKeys, salt)); } function _salt( address entryPoint, uint8 scheme, uint8 threshold, bytes[] calldata pubKeys, bytes32 salt ) internal pure returns (bytes32) { return keccak256(abi.encode(entryPoint, scheme, threshold, keccak256(abi.encode(pubKeys)), salt)); } function _addressFor(bytes32 create2Salt) internal view returns (address) { bytes32 h = keccak256( abi.encodePacked(bytes1(0xff), address(this), create2Salt, keccak256(type(AereThresholdAccount).creationCode)) ); return address(uint160(uint256(h))); } }