@@ -12,11 +12,12 @@ import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";
12
12
/// @author Euler Labs (https://www.eulerlabs.com/)
13
13
contract EulerSwapFactory is IEulerSwapFactory , EVCUtil {
14
14
/// @dev An array to store all pools addresses.
15
- address [] public allPools;
16
- /// @dev Mapping between euler account and deployed pool that is currently set as operator
17
- mapping (address eulerAccount = > address operator ) public eulerAccountToPool;
15
+ address [] private allPools;
18
16
/// @dev Vaults must be deployed by this factory
19
17
address public immutable evkFactory;
18
+ /// @dev Mapping between euler account and EulerAccountState
19
+ mapping (address eulerAccount = > EulerAccountState state ) private eulerAccountState;
20
+ mapping (address asset0 = > mapping (address asset1 = > address [])) private poolMap;
20
21
21
22
IPoolManager immutable poolManager;
22
23
@@ -25,7 +26,7 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
25
26
address indexed asset1 ,
26
27
address vault0 ,
27
28
address vault1 ,
28
- uint256 indexed feeMultiplier ,
29
+ uint256 indexed fee ,
29
30
address eulerAccount ,
30
31
uint256 reserve0 ,
31
32
uint256 reserve1 ,
@@ -35,12 +36,14 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
35
36
uint256 concentrationY ,
36
37
address pool
37
38
);
39
+ event PoolUninstalled (address indexed asset0 , address indexed asset1 , address indexed eulerAccount , address pool );
38
40
39
41
error InvalidQuery ();
40
42
error Unauthorized ();
41
43
error OldOperatorStillInstalled ();
42
44
error OperatorNotInstalled ();
43
45
error InvalidVaultImplementation ();
46
+ error SliceOutOfBounds ();
44
47
45
48
constructor (IPoolManager _manager , address evc , address evkFactory_ ) EVCUtil (evc) {
46
49
poolManager = _manager;
@@ -58,12 +61,12 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
58
61
InvalidVaultImplementation ()
59
62
);
60
63
64
+ uninstall (params.eulerAccount);
65
+
61
66
EulerSwapHook pool =
62
67
new EulerSwapHook {salt: keccak256 (abi.encode (params.eulerAccount, salt))}(poolManager, params, curveParams);
63
68
64
- checkEulerAccountOperators (params.eulerAccount, address (pool));
65
-
66
- allPools.push (address (pool));
69
+ updateEulerAccountState (params.eulerAccount, address (pool));
67
70
68
71
pool.activate ();
69
72
@@ -72,7 +75,7 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
72
75
pool.asset1 (),
73
76
params.vault0,
74
77
params.vault1,
75
- pool.feeMultiplier (),
78
+ pool.fee (),
76
79
params.eulerAccount,
77
80
params.currReserve0,
78
81
params.currReserve1,
@@ -86,6 +89,11 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
86
89
return address (pool);
87
90
}
88
91
92
+ /// @inheritdoc IEulerSwapFactory
93
+ function uninstallPool () external {
94
+ uninstall (_msgSender ());
95
+ }
96
+
89
97
/// @inheritdoc IEulerSwapFactory
90
98
function computePoolAddress (
91
99
IEulerSwap.Params memory poolParams ,
@@ -112,43 +120,127 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
112
120
);
113
121
}
114
122
123
+ /// @inheritdoc IEulerSwapFactory
115
124
function EVC () external view override (EVCUtil, IEulerSwapFactory) returns (address ) {
116
125
return address (evc);
117
126
}
118
127
119
128
/// @inheritdoc IEulerSwapFactory
120
- function allPoolsLength () external view returns (uint256 ) {
129
+ function poolByEulerAccount (address eulerAccount ) external view returns (address ) {
130
+ return eulerAccountState[eulerAccount].pool;
131
+ }
132
+
133
+ /// @inheritdoc IEulerSwapFactory
134
+ function poolsLength () external view returns (uint256 ) {
121
135
return allPools.length ;
122
136
}
123
137
124
138
/// @inheritdoc IEulerSwapFactory
125
- function getAllPoolsListSlice (uint256 _start , uint256 _end ) external view returns (address [] memory ) {
126
- uint256 length = allPools.length ;
127
- if (_end == type (uint256 ).max) _end = length;
128
- if (_end < _start || _end > length) revert InvalidQuery ();
129
-
130
- address [] memory allPoolsList = new address [](_end - _start);
131
- for (uint256 i; i < _end - _start; ++ i) {
132
- allPoolsList[i] = allPools[_start + i];
133
- }
139
+ function poolsSlice (uint256 start , uint256 end ) external view returns (address [] memory ) {
140
+ return _getSlice (allPools, start, end);
141
+ }
142
+
143
+ /// @inheritdoc IEulerSwapFactory
144
+ function pools () external view returns (address [] memory ) {
145
+ return _getSlice (allPools, 0 , type (uint256 ).max);
146
+ }
147
+
148
+ /// @inheritdoc IEulerSwapFactory
149
+ function poolsByPairLength (address asset0 , address asset1 ) external view returns (uint256 ) {
150
+ return poolMap[asset0][asset1].length ;
151
+ }
152
+
153
+ /// @inheritdoc IEulerSwapFactory
154
+ function poolsByPairSlice (address asset0 , address asset1 , uint256 start , uint256 end )
155
+ external
156
+ view
157
+ returns (address [] memory )
158
+ {
159
+ return _getSlice (poolMap[asset0][asset1], start, end);
160
+ }
134
161
135
- return allPoolsList;
162
+ /// @inheritdoc IEulerSwapFactory
163
+ function poolsByPair (address asset0 , address asset1 ) external view returns (address [] memory ) {
164
+ return _getSlice (poolMap[asset0][asset1], 0 , type (uint256 ).max);
136
165
}
137
166
138
- /// @notice Validates operator authorization for euler account. First checks if the account has an existing operator
139
- /// and ensures it is deauthorized. Then verifies the new pool is authorized as an operator. Finally, updates the
140
- /// mapping to track the new pool as the account's operator.
167
+ /// @notice Validates operator authorization for euler account and update the relevant EulerAccountState.
141
168
/// @param eulerAccount The address of the euler account.
142
- /// @param newPool The address of the new pool.
143
- function checkEulerAccountOperators (address eulerAccount , address newPool ) internal {
144
- address operator = eulerAccountToPool[eulerAccount] ;
169
+ /// @param newOperator The address of the new pool.
170
+ function updateEulerAccountState (address eulerAccount , address newOperator ) internal {
171
+ require (evc. isAccountOperatorAuthorized (eulerAccount, newOperator), OperatorNotInstalled ()) ;
145
172
146
- if (operator != address (0 )) {
147
- require (! evc.isAccountOperatorAuthorized (eulerAccount, operator), OldOperatorStillInstalled ());
148
- }
173
+ (address asset0 , address asset1 ) = _getAssets (newOperator);
174
+
175
+ address [] storage poolMapArray = poolMap[asset0][asset1];
176
+
177
+ eulerAccountState[eulerAccount] = EulerAccountState ({
178
+ pool: newOperator,
179
+ allPoolsIndex: uint48 (allPools.length ),
180
+ poolMapIndex: uint48 (poolMapArray.length )
181
+ });
182
+
183
+ allPools.push (newOperator);
184
+ poolMapArray.push (newOperator);
185
+ }
186
+
187
+ /// @notice Uninstalls the pool associated with the given Euler account
188
+ /// @dev This function removes the pool from the factory's tracking and emits a PoolUninstalled event
189
+ /// @dev The function checks if the operator is still installed and reverts if it is
190
+ /// @dev If no pool exists for the account, the function returns without any action
191
+ /// @param eulerAccount The address of the Euler account whose pool should be uninstalled
192
+ function uninstall (address eulerAccount ) internal {
193
+ address pool = eulerAccountState[eulerAccount].pool;
194
+
195
+ if (pool == address (0 )) return ;
196
+
197
+ require (! evc.isAccountOperatorAuthorized (eulerAccount, pool), OldOperatorStillInstalled ());
198
+
199
+ (address asset0 , address asset1 ) = _getAssets (pool);
149
200
150
- require (evc.isAccountOperatorAuthorized (eulerAccount, newPool), OperatorNotInstalled ());
201
+ address [] storage poolMapArr = poolMap[asset0][asset1];
202
+
203
+ swapAndPop (allPools, eulerAccountState[eulerAccount].allPoolsIndex);
204
+ swapAndPop (poolMapArr, eulerAccountState[eulerAccount].poolMapIndex);
205
+
206
+ delete eulerAccountState[eulerAccount];
207
+
208
+ emit PoolUninstalled (asset0, asset1, eulerAccount, pool);
209
+ }
210
+
211
+ /// @notice Swaps the element at the given index with the last element and removes the last element
212
+ /// @param arr The storage array to modify
213
+ /// @param index The index of the element to remove
214
+ function swapAndPop (address [] storage arr , uint256 index ) internal {
215
+ arr[index] = arr[arr.length - 1 ];
216
+ arr.pop ();
217
+ }
218
+
219
+ /// @notice Retrieves the asset addresses for a given pool
220
+ /// @dev Calls the pool contract to get its asset0 and asset1 addresses
221
+ /// @param pool The address of the pool to query
222
+ /// @return The addresses of asset0 and asset1 in the pool
223
+ function _getAssets (address pool ) internal view returns (address , address ) {
224
+ return (EulerSwap (pool).asset0 (), EulerSwap (pool).asset1 ());
225
+ }
226
+
227
+ /// @notice Returns a slice of an array of addresses
228
+ /// @dev Creates a new memory array containing elements from start to end index
229
+ /// If end is type(uint256).max, it will return all elements from start to the end of the array
230
+ /// @param arr The storage array to slice
231
+ /// @param start The starting index of the slice (inclusive)
232
+ /// @param end The ending index of the slice (exclusive)
233
+ /// @return A new memory array containing the requested slice of addresses
234
+ function _getSlice (address [] storage arr , uint256 start , uint256 end ) internal view returns (address [] memory ) {
235
+ uint256 length = arr.length ;
236
+ if (end == type (uint256 ).max) end = length;
237
+ if (end < start || end > length) revert SliceOutOfBounds ();
238
+
239
+ address [] memory slice = new address [](end - start);
240
+ for (uint256 i; i < end - start; ++ i) {
241
+ slice[i] = arr[start + i];
242
+ }
151
243
152
- eulerAccountToPool[eulerAccount] = newPool ;
244
+ return slice ;
153
245
}
154
246
}
0 commit comments