Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
55 lines
2.3 KiB
Solidity
55 lines
2.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {AereModularAccount} from "./AereModularAccount.sol";
|
|
|
|
/// @title AereModularAccountFactory - CREATE2 factory for AereModularAccount
|
|
/// @notice Deterministic: getAddress(rootOwner, salt) equals the deployed address.
|
|
/// The root owner is mixed into the CREATE2 salt so nobody can front-run
|
|
/// a counterfactual address with a different owner. Follows the
|
|
/// AerePasskeyAccountFactoryV2 conventions (idempotent createAccount,
|
|
/// immutable default EntryPoint).
|
|
contract AereModularAccountFactory {
|
|
bytes32 public constant ACCOUNT_INIT_CODE_HASH = keccak256(type(AereModularAccount).creationCode);
|
|
|
|
/// @notice The EntryPoint every account created by this factory trusts.
|
|
address public immutable defaultEntryPoint;
|
|
|
|
event AccountCreated(address indexed account, address indexed rootOwner, address indexed entryPoint, uint256 salt);
|
|
|
|
error ZeroEntryPoint();
|
|
error AddressMismatch();
|
|
|
|
constructor(address _defaultEntryPoint) {
|
|
if (_defaultEntryPoint == address(0)) revert ZeroEntryPoint();
|
|
defaultEntryPoint = _defaultEntryPoint;
|
|
}
|
|
|
|
/// @notice Deterministic counterfactual address for (rootOwner, salt).
|
|
function getAddress(address rootOwner, uint256 salt) public view returns (address) {
|
|
bytes32 saltMix = _saltMix(rootOwner, salt);
|
|
return address(uint160(uint256(keccak256(abi.encodePacked(
|
|
bytes1(0xff), address(this), saltMix, ACCOUNT_INIT_CODE_HASH
|
|
)))));
|
|
}
|
|
|
|
/// @notice Idempotent: returns the existing account if already deployed.
|
|
function createAccount(address rootOwner, uint256 salt)
|
|
external
|
|
returns (AereModularAccount account)
|
|
{
|
|
address predicted = getAddress(rootOwner, salt);
|
|
if (predicted.code.length > 0) {
|
|
return AereModularAccount(payable(predicted));
|
|
}
|
|
account = new AereModularAccount{salt: _saltMix(rootOwner, salt)}();
|
|
account.initialize(defaultEntryPoint, rootOwner);
|
|
if (address(account) != predicted) revert AddressMismatch();
|
|
emit AccountCreated(address(account), rootOwner, defaultEntryPoint, salt);
|
|
}
|
|
|
|
function _saltMix(address rootOwner, uint256 salt) internal pure returns (bytes32) {
|
|
return keccak256(abi.encode(rootOwner, salt));
|
|
}
|
|
}
|