From 14279f8589ed54e64f73022178d6005addede7a9 Mon Sep 17 00:00:00 2001 From: Filipp Makarov Date: Thu, 9 Jan 2025 15:19:00 +0300 Subject: [PATCH] add new method to k1 --- contracts/common/Stakeable.sol | 24 +++++++++----------- contracts/factory/BiconomyMetaFactory.sol | 2 +- contracts/factory/K1ValidatorFactory.sol | 26 ++++++++++++++++++++-- contracts/factory/NexusAccountFactory.sol | 2 +- contracts/factory/RegistryFactory.sol | 4 +++- contracts/interfaces/common/IStakeable.sol | 9 +++----- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/contracts/common/Stakeable.sol b/contracts/common/Stakeable.sol index a08023cf..bc79db14 100644 --- a/contracts/common/Stakeable.sol +++ b/contracts/common/Stakeable.sol @@ -28,33 +28,31 @@ contract Stakeable is Ownable, IStakeable { /// @notice Error thrown when an invalid EntryPoint address is provided. error InvalidEntryPointAddress(); - constructor(address newOwner) { + address public immutable ENTRY_POINT; + + constructor(address newOwner, address entryPoint) { _setOwner(newOwner); + require(entryPoint != address(0), InvalidEntryPointAddress()); + ENTRY_POINT = entryPoint; } /// @notice Stakes a certain amount of Ether on an EntryPoint. /// @dev The contract should have enough Ether to cover the stake. - /// @param epAddress The address of the EntryPoint where the stake is added. /// @param unstakeDelaySec The delay in seconds before the stake can be unlocked. - function addStake(address epAddress, uint32 unstakeDelaySec) external payable onlyOwner { - require(epAddress != address(0), InvalidEntryPointAddress()); - IEntryPoint(epAddress).addStake{ value: msg.value }(unstakeDelaySec); + function addStake(uint32 unstakeDelaySec) external payable onlyOwner { + IEntryPoint(ENTRY_POINT).addStake{ value: msg.value }(unstakeDelaySec); } /// @notice Unlocks the stake on an EntryPoint. /// @dev This starts the unstaking delay after which funds can be withdrawn. - /// @param epAddress The address of the EntryPoint from which the stake is to be unlocked. - function unlockStake(address epAddress) external onlyOwner { - require(epAddress != address(0), InvalidEntryPointAddress()); - IEntryPoint(epAddress).unlockStake(); + function unlockStake() external onlyOwner { + IEntryPoint(ENTRY_POINT).unlockStake(); } /// @notice Withdraws the stake from an EntryPoint to a specified address. /// @dev This can only be done after the unstaking delay has passed since the unlock. - /// @param epAddress The address of the EntryPoint where the stake is withdrawn from. /// @param withdrawAddress The address to receive the withdrawn stake. - function withdrawStake(address epAddress, address payable withdrawAddress) external onlyOwner { - require(epAddress != address(0), InvalidEntryPointAddress()); - IEntryPoint(epAddress).withdrawStake(withdrawAddress); + function withdrawStake(address payable withdrawAddress) external onlyOwner { + IEntryPoint(ENTRY_POINT).withdrawStake(withdrawAddress); } } diff --git a/contracts/factory/BiconomyMetaFactory.sol b/contracts/factory/BiconomyMetaFactory.sol index 42200dab..ff256b1a 100644 --- a/contracts/factory/BiconomyMetaFactory.sol +++ b/contracts/factory/BiconomyMetaFactory.sol @@ -43,7 +43,7 @@ contract BiconomyMetaFactory is Stakeable { /// @notice Constructor to set the owner of the contract. /// @param owner_ The address of the owner. - constructor(address owner_) Stakeable(owner_) { + constructor(address owner_, address entryPoint) Stakeable(owner_, entryPoint) { require(owner_ != address(0), ZeroAddressNotAllowed()); } diff --git a/contracts/factory/K1ValidatorFactory.sol b/contracts/factory/K1ValidatorFactory.sol index b9d6713e..4132d693 100644 --- a/contracts/factory/K1ValidatorFactory.sol +++ b/contracts/factory/K1ValidatorFactory.sol @@ -46,12 +46,24 @@ contract K1ValidatorFactory is Stakeable { /// @notice Error thrown when a zero address is provided for the implementation, K1 validator, or bootstrapper. error ZeroAddressNotAllowed(); + /// @notice Error thrown when the createAccount function is called by a non-EntryPoint. + error EntryPointOnly(); + /// @notice Constructor to set the immutable variables. /// @param implementation The address of the Nexus implementation to be used for all deployments. /// @param factoryOwner The address of the factory owner. /// @param k1Validator The address of the K1 Validator module to be used for all deployments. /// @param bootstrapper The address of the Bootstrapper module to be used for all deployments. - constructor(address implementation, address factoryOwner, address k1Validator, NexusBootstrap bootstrapper, IERC7484 registry) Stakeable(factoryOwner) { + constructor( + address implementation, + address factoryOwner, + address entryPoint, + address k1Validator, + NexusBootstrap bootstrapper, + IERC7484 registry + ) + Stakeable(factoryOwner, entryPoint) + { require( !(implementation == address(0) || k1Validator == address(0) || address(bootstrapper) == address(0) || factoryOwner == address(0)), ZeroAddressNotAllowed() @@ -62,7 +74,7 @@ contract K1ValidatorFactory is Stakeable { REGISTRY = registry; } - /// @notice Creates a new Nexus with a specific validator and initialization data. + /// @notice Creates a new Nexus with K1 validator and initialization data. /// @param eoaOwner The address of the EOA owner of the Nexus. /// @param index The index of the Nexus. /// @param attesters The list of attesters for the Nexus. @@ -84,6 +96,16 @@ contract K1ValidatorFactory is Stakeable { return account; } + /// @notice Creates a new Nexus with K1 validator and initialization data by the EntryPoint. + /// @dev same as createAccount but should be called by the EntryPoint + /// Wallets should use this method to prevent front-running userOp.initcode execution which can lead the whole userOp to fail + /// See AA-466 for more details https://github.com/eth-infinitism/account-abstraction/pull/514 + function createAccountByEP(address eoaOwner, uint256 index, address[] calldata attesters, uint8 threshold) external payable returns (address payable) { + require(msg.sender == IEntryPoint(ENTRY_POINT).senderCreator(), EntryPointOnly()); + return createAccount(eoaOwner, index, attesters, threshold); + } + + /// @notice Computes the expected address of a Nexus contract using the factory's deterministic deployment algorithm. /// @notice Computes the expected address of a Nexus contract using the factory's deterministic deployment algorithm. /// @param eoaOwner The address of the EOA owner of the Nexus. /// @param index The index of the Nexus. diff --git a/contracts/factory/NexusAccountFactory.sol b/contracts/factory/NexusAccountFactory.sol index 980ea7f7..c1391490 100644 --- a/contracts/factory/NexusAccountFactory.sol +++ b/contracts/factory/NexusAccountFactory.sol @@ -31,7 +31,7 @@ contract NexusAccountFactory is Stakeable, INexusFactory { /// @notice Constructor to set the smart account implementation address and the factory owner. /// @param implementation_ The address of the Nexus implementation to be used for all deployments. /// @param owner_ The address of the owner of the factory. - constructor(address implementation_, address owner_) Stakeable(owner_) { + constructor(address implementation_, address owner_, address entryPoint) Stakeable(owner_, entryPoint) { require(implementation_ != address(0), ImplementationAddressCanNotBeZero()); require(owner_ != address(0), ZeroAddressNotAllowed()); ACCOUNT_IMPLEMENTATION = implementation_; diff --git a/contracts/factory/RegistryFactory.sol b/contracts/factory/RegistryFactory.sol index b22a16b2..66ad64a7 100644 --- a/contracts/factory/RegistryFactory.sol +++ b/contracts/factory/RegistryFactory.sol @@ -49,7 +49,9 @@ contract RegistryFactory is Stakeable, INexusFactory { /// @notice Constructor to set the smart account implementation address and owner. /// @param implementation_ The address of the Nexus implementation to be used for all deployments. /// @param owner_ The address of the owner of the factory. - constructor(address implementation_, address owner_, IERC7484 registry_, address[] memory attesters_, uint8 threshold_) Stakeable(owner_) { + constructor(address implementation_, address owner_, address entryPoint, IERC7484 registry_, address[] memory attesters_, uint8 threshold_) + Stakeable(owner_, entryPoint) + { require(implementation_ != address(0), ImplementationAddressCanNotBeZero()); require(owner_ != address(0), ZeroAddressNotAllowed()); require(threshold_ <= attesters_.length, InvalidThreshold(threshold_, attesters_.length)); diff --git a/contracts/interfaces/common/IStakeable.sol b/contracts/interfaces/common/IStakeable.sol index 94a2e15f..f0560d08 100644 --- a/contracts/interfaces/common/IStakeable.sol +++ b/contracts/interfaces/common/IStakeable.sol @@ -23,18 +23,15 @@ pragma solidity ^0.8.27; interface IStakeable { /// @notice Stakes a certain amount of Ether on an EntryPoint. /// @dev The contract should have enough Ether to cover the stake. - /// @param epAddress The address of the EntryPoint where the stake is added. /// @param unstakeDelaySec The delay in seconds before the stake can be unlocked. - function addStake(address epAddress, uint32 unstakeDelaySec) external payable; + function addStake(uint32 unstakeDelaySec) external payable; /// @notice Unlocks the stake on an EntryPoint. /// @dev This starts the unstaking delay after which funds can be withdrawn. - /// @param epAddress The address of the EntryPoint from which the stake is to be unlocked. - function unlockStake(address epAddress) external; + function unlockStake() external; /// @notice Withdraws the stake from an EntryPoint to a specified address. /// @dev This can only be done after the unstaking delay has passed since the unlock. - /// @param epAddress The address of the EntryPoint where the stake is withdrawn from. /// @param withdrawAddress The address to receive the withdrawn stake. - function withdrawStake(address epAddress, address payable withdrawAddress) external; + function withdrawStake(address payable withdrawAddress) external; }