@@ -4,45 +4,132 @@ pragma solidity ^0.8.12;
44// Utils
55import "../extension/Multicall.sol " ;
66import "@openzeppelin/contracts/proxy/Clones.sol " ;
7+ import "../lib/TWStringSet.sol " ;
78
89// Interface
910import "./interfaces/ITWAccountFactory.sol " ;
1011
1112// Smart wallet implementation
1213import "./TWDynamicAccount.sol " ;
1314
15+ // $$\ $$\ $$\ $$\ $$\
16+ // $$ | $$ | \__| $$ | $$ |
17+ // $$$$$$\ $$$$$$$\ $$\ $$$$$$\ $$$$$$$ |$$\ $$\ $$\ $$$$$$\ $$$$$$$\
18+ // \_$$ _| $$ __$$\ $$ |$$ __$$\ $$ __$$ |$$ | $$ | $$ |$$ __$$\ $$ __$$\
19+ // $$ | $$ | $$ |$$ |$$ | \__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
20+ // $$ |$$\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
21+ // \$$$$ |$$ | $$ |$$ |$$ | \$$$$$$$ |\$$$$$\$$$$ |\$$$$$$$\ $$$$$$$ |
22+ // \____/ \__| \__|\__|\__| \_______| \_____\____/ \_______|\_______/
23+
24+ /*///////////////////////////////////////////////////////////////
25+ Storage layout
26+ //////////////////////////////////////////////////////////////*/
27+
28+ library TWDynamicAccountFactoryStorage {
29+ bytes32 internal constant DYNAMIC_ACCOUNT_FACTORY_STORAGE_POSITION =
30+ keccak256 ("tw.dynamic.account.factory.storage " );
31+
32+ struct Data {
33+ TWStringSet.Set allAccounts;
34+ mapping (address => TWStringSet.Set) accountsOfSigner;
35+ }
36+
37+ function factoryStorage () internal pure returns (Data storage dynamicAccountFactoryData ) {
38+ bytes32 position = DYNAMIC_ACCOUNT_FACTORY_STORAGE_POSITION;
39+ assembly {
40+ dynamicAccountFactoryData.slot := position
41+ }
42+ }
43+ }
44+
1445contract TWDynamicAccountFactory is ITWAccountFactory , Multicall {
46+ using TWStringSet for TWStringSet.Set;
47+
48+ /*///////////////////////////////////////////////////////////////
49+ State
50+ //////////////////////////////////////////////////////////////*/
51+
1552 TWDynamicAccount private immutable _accountImplementation;
1653
54+ /*///////////////////////////////////////////////////////////////
55+ Constructor
56+ //////////////////////////////////////////////////////////////*/
57+
1758 constructor (IEntryPoint _entrypoint ) {
1859 _accountImplementation = new TWDynamicAccount (_entrypoint);
1960 }
2061
21- /// @notice Returns the implementation of the Account.
22- function accountImplementation () external view override returns (address ) {
23- return address (_accountImplementation);
24- }
62+ /*///////////////////////////////////////////////////////////////
63+ External functions
64+ //////////////////////////////////////////////////////////////*/
2565
26- /// @notice Deploys a new Account with the given admin and salt.
27- function createAccount (address _admin , bytes32 _salt ) external returns (address ) {
66+ /// @notice Deploys a new Account with the given admin and accountId used as salt.
67+ function createAccount (address _admin , string memory _accountId ) external returns (address ) {
2868 address impl = address (_accountImplementation);
29- address account = Clones.predictDeterministicAddress (impl, _salt);
69+ bytes32 salt = keccak256 (abi.encode (_accountId));
70+ address account = Clones.predictDeterministicAddress (impl, salt);
3071
3172 if (account.code.length > 0 ) {
3273 return account;
3374 }
3475
35- account = Clones.cloneDeterministic (impl, _salt );
76+ account = Clones.cloneDeterministic (impl, salt );
3677
3778 TWAccount (payable (account)).initialize (_admin);
3879
39- emit AccountCreated (account, _admin, _salt);
80+ _setupAccount (_admin, _accountId);
81+
82+ emit AccountCreated (account, _admin, _accountId);
4083
4184 return account;
4285 }
4386
44- /// @notice Returns the address of an Account that would be deployed with the given salt.
45- function getAddress (bytes32 _salt ) external view returns (address ) {
46- return Clones.predictDeterministicAddress (address (_accountImplementation), _salt);
87+ /*///////////////////////////////////////////////////////////////
88+ View functions
89+ //////////////////////////////////////////////////////////////*/
90+
91+ /// @notice Returns the implementation of the Account.
92+ function accountImplementation () external view override returns (address ) {
93+ return address (_accountImplementation);
94+ }
95+
96+ /// @notice Returns the address of an Account that would be deployed with the given accountId as salt.
97+ function getAddress (string memory _accountId ) public view returns (address ) {
98+ bytes32 salt = keccak256 (abi.encode (_accountId));
99+ return Clones.predictDeterministicAddress (address (_accountImplementation), salt);
100+ }
101+
102+ /// @notice Returns the list of accounts created by a signer.
103+ function getAccountsOfSigner (address _signer ) external view returns (AccountInfo[] memory ) {
104+ TWDynamicAccountFactoryStorage.Data storage data = TWDynamicAccountFactoryStorage.factoryStorage ();
105+ return _formatAccounts (data.accountsOfSigner[_signer].values ());
106+ }
107+
108+ /// @notice Returns the list of all accounts.
109+ function getAllAccounts () external view returns (AccountInfo[] memory accounts ) {
110+ TWDynamicAccountFactoryStorage.Data storage data = TWDynamicAccountFactoryStorage.factoryStorage ();
111+ return _formatAccounts (data.allAccounts.values ());
112+ }
113+
114+ /*///////////////////////////////////////////////////////////////
115+ Internal functions
116+ //////////////////////////////////////////////////////////////*/
117+
118+ /// @dev Formats a list of accountIds to a list of `AccountInfo` (account id + account address).
119+ function _formatAccounts (string [] memory _accountIds ) internal view returns (AccountInfo[] memory accounts ) {
120+ uint256 len = _accountIds.length ;
121+ accounts = new AccountInfo [](len);
122+ for (uint256 i = 0 ; i < len; i += 1 ) {
123+ string memory accountId = _accountIds[i];
124+ address account = getAddress (accountId);
125+ accounts[i] = AccountInfo (accountId, account);
126+ }
127+ }
128+
129+ /// @dev Adds an account to the list of accounts created by a signer.
130+ function _setupAccount (address _signer , string memory _accountId ) internal {
131+ TWDynamicAccountFactoryStorage.Data storage data = TWDynamicAccountFactoryStorage.factoryStorage ();
132+ data.allAccounts.add (_accountId);
133+ data.accountsOfSigner[_signer].add (_accountId);
47134 }
48135}
0 commit comments