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