Skip to content

Commit a0d3e5c

Browse files
feat: setup initial test bases
1 parent 0bec6dc commit a0d3e5c

16 files changed

+1114
-11
lines changed

.gas-snapshot

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
IntegrationGreeter:test_Greet() (gas: 27808)
2+
TestAccountConfig_AccountId:test_WhenCheckingTheAccountID() (gas: 10039)
3+
TestAccountConfig_SupportsExecutionMode:test_RevertIf_UnsupportedExecutionMode() (gas: 14687)
4+
TestAccountConfig_SupportsExecutionMode:test_SupportsBatchExecutionMode_Success() (gas: 14463)
5+
TestAccountConfig_SupportsExecutionMode:test_SupportsSingleExecutionMode_Success() (gas: 14552)
6+
UnitGreeter:test_ConstructorWhenPassingAnEmptyGreetingString() (gas: 68737)
7+
UnitGreeter:test_ConstructorWhenPassingValidGreetingString() (gas: 500951)
8+
UnitGreeter:test_EmptyTestExample() (gas: 0)
9+
UnitGreeter:test_GreetWhenCalled() (gas: 23509)
10+
UnitGreeter:test_SetGreetingWhenCalledByANon_owner(address) (runs: 1000, μ: 11815, ~: 11815)
11+
UnitGreeter:test_SetGreetingWhenPassingAValidGreetingString() (gas: 23570)
12+
UnitGreeter:test_SetGreetingWhenPassingAnEmptyGreetingString() (gas: 11763)
Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,50 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.28;
33

4-
// Generic Account Factory which can deploy SA with more modules (multiple validation schemes, executors, hooks etc upon deployment itself)
4+
import {IStartaleAccountFactory} from '../interfaces/IStartaleAccountFactory.sol';
5+
import {ProxyLib} from '../lib/ProxyLib.sol';
6+
import {Stakeable} from '../utils/Stakeable.sol';
7+
8+
/// @title Startale Account Factory
9+
/// @dev Generic Account Factory which can deploy SA with more modules (multiple validation schemes, executors, hooks etc upon deployment itself)
10+
/// @notice Manages the creation of Modular Smart Accounts compliant with ERC-7579 and ERC-4337 using a factory pattern.
11+
/// @author Startale labs
12+
contract StartaleAccountFactory is Stakeable, IStartaleAccountFactory {
13+
/// @notice Address of the implementation contract used to create new Startale Account instances.
14+
/// @dev This address is immutable and set upon deployment, ensuring the implementation cannot be changed.
15+
address public immutable ACCOUNT_IMPLEMENTATION;
16+
17+
/// @notice Constructor to set the smart account implementation address and the factory owner.
18+
/// @param implementation_ The address of the Startale Account implementation to be used for all deployments.
19+
/// @param owner_ The address of the owner of the factory.
20+
constructor(address implementation_, address owner_) Stakeable(owner_) {
21+
require(implementation_ != address(0), ImplementationAddressCanNotBeZero());
22+
require(owner_ != address(0), ZeroAddressNotAllowed());
23+
ACCOUNT_IMPLEMENTATION = implementation_;
24+
}
25+
26+
/// @notice Creates a new Startale Account with the provided initialization data.
27+
/// @param initData Initialization data to be called on the new Smart Account.
28+
/// @param salt Unique salt for the Smart Account creation.
29+
/// @return The address of the newly created Startale Account.
30+
function createAccount(bytes calldata initData, bytes32 salt) external payable override returns (address payable) {
31+
// Deploy the Startale Account using the ProxyLib
32+
(bool alreadyDeployed, address payable account) = ProxyLib.deployProxy(ACCOUNT_IMPLEMENTATION, salt, initData);
33+
if (!alreadyDeployed) {
34+
emit AccountCreated(account, initData, salt);
35+
}
36+
return account;
37+
}
38+
39+
/// @notice Computes the expected address of a Startale Account using the factory's deterministic deployment algorithm.
40+
/// @param initData - Initialization data to be called on the new Smart Account.
41+
/// @param salt - Unique salt for the Smart Account creation.
42+
/// @return expectedAddress The expected address at which the Startale Account will be deployed if the provided parameters are used.
43+
function computeAccountAddress(
44+
bytes calldata initData,
45+
bytes32 salt
46+
) external view override returns (address payable expectedAddress) {
47+
// Return the expected address of the Startale Account using the provided initialization data and salt
48+
return ProxyLib.predictProxyAddress(ACCOUNT_IMPLEMENTATION, salt, initData);
49+
}
50+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
/// @title Interface for Generic Startale Account Factory
5+
/// @notice Interface that provides the essential structure for account factories.
6+
/// @author Startale labs
7+
interface IStartaleAccountFactory {
8+
/// @notice Emitted when a new Smart Account is created.
9+
/// @param account The address of the newly created account.
10+
/// @param initData Initialization data used for the new Smart Account.
11+
/// @param salt Unique salt used during the creation of the Smart Account.
12+
event AccountCreated(address indexed account, bytes indexed initData, bytes32 indexed salt);
13+
14+
/// @notice Error indicating that the account is already deployed
15+
/// @param account The address of the account that is already deployed
16+
error AccountAlreadyDeployed(address account);
17+
18+
/// @notice Error thrown when the owner address is zero.
19+
error ZeroAddressNotAllowed();
20+
21+
/// @notice Error thrown when the implementation address is zero.
22+
error ImplementationAddressCanNotBeZero();
23+
24+
/// @notice Creates a new Startale Account with initialization data.
25+
/// @param initData Initialization data to be called on the new Smart Account.
26+
/// @param salt Unique salt for the Smart Account creation.
27+
/// @return The address of the newly created Startale Account.
28+
function createAccount(bytes calldata initData, bytes32 salt) external payable returns (address payable);
29+
30+
/// @notice Computes the expected address of a Startale Account using the factory's deterministic deployment algorithm.
31+
/// @param initData Initialization data to be called on the new Smart Account.
32+
/// @param salt Unique salt for the Smart Account creation.
33+
/// @return expectedAddress The expected address at which the Startale Account will be deployed if the provided parameters are used.
34+
function computeAccountAddress(
35+
bytes calldata initData,
36+
bytes32 salt
37+
) external view returns (address payable expectedAddress);
38+
}

src/lib/ModuleTypeLib.sol

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.28;
3+
4+
type EncodedModuleTypes is uint256;
5+
6+
type ModuleType is uint8;
7+
8+
/// @title ModuleTypeLib
9+
/// @notice A library for handling module types and encoding them as bits
10+
library ModuleTypeLib {
11+
/// @notice Checks if the given EncodedModuleTypes contains a specific module type
12+
/// @param self The encoded module types
13+
/// @param moduleTypeId The module type to check for
14+
/// @return True if the module type is present, false otherwise
15+
function isType(EncodedModuleTypes self, ModuleType moduleTypeId) internal pure returns (bool) {
16+
// Check if the specific bit for the moduleTypeId is set in the encoded value using bitwise shift
17+
return (EncodedModuleTypes.unwrap(self) & (uint256(1) << ModuleType.unwrap(moduleTypeId))) != 0;
18+
}
19+
20+
/// @notice Encodes an array of ModuleType into a single EncodedModuleTypes bitmask
21+
/// @param moduleTypes An array of ModuleType to encode
22+
/// @return The encoded module types
23+
// example for bitEncode, similar adjustments should be done for isType, bitEncodeCalldata
24+
function bitEncode(ModuleType[] memory moduleTypes) internal pure returns (EncodedModuleTypes) {
25+
uint256 result;
26+
27+
// Iterate through the moduleTypes array and set the corresponding bits in the result
28+
for (uint256 i; i < moduleTypes.length; i++) {
29+
result |= uint256(1) << ModuleType.unwrap(moduleTypes[i]);
30+
}
31+
32+
return EncodedModuleTypes.wrap(result);
33+
}
34+
35+
/// @notice Encodes a calldata array of ModuleType into a single EncodedModuleTypes bitmask
36+
/// @param moduleTypes A calldata array of ModuleType to encode
37+
/// @return The encoded module types
38+
function bitEncodeCalldata(ModuleType[] calldata moduleTypes) internal pure returns (EncodedModuleTypes) {
39+
uint256 result;
40+
41+
// Iterate through the moduleTypes array and set the corresponding bits in the result
42+
for (uint256 i; i < moduleTypes.length; i++) {
43+
result |= uint256(1) << ModuleType.unwrap(moduleTypes[i]);
44+
}
45+
46+
return EncodedModuleTypes.wrap(result);
47+
}
48+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

test/foundry/mocks/MockHandler.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

test/foundry/mocks/MockHook.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

test/foundry/mocks/MockTarget.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)