@@ -11,11 +11,12 @@ import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";
1111/// @author Euler Labs (https://www.eulerlabs.com/)
1212contract EulerSwapFactory is IEulerSwapFactory , EVCUtil {
1313 /// @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;
1715 /// @dev Vaults must be deployed by this factory
1816 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;
1920
2021 event PoolDeployed (
2122 address indexed asset0 ,
@@ -32,12 +33,14 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
3233 uint256 concentrationY ,
3334 address pool
3435 );
36+ event PoolUninstalled (address indexed asset0 , address indexed asset1 , address indexed eulerAccount , address pool );
3537
3638 error InvalidQuery ();
3739 error Unauthorized ();
3840 error OldOperatorStillInstalled ();
3941 error OperatorNotInstalled ();
4042 error InvalidVaultImplementation ();
43+ error SliceOutOfBounds ();
4144
4245 constructor (address evc , address evkFactory_ ) EVCUtil (evc) {
4346 evkFactory = evkFactory_;
@@ -54,11 +57,11 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
5457 InvalidVaultImplementation ()
5558 );
5659
57- EulerSwap pool = new EulerSwap {salt: keccak256 ( abi.encode ( params.eulerAccount, salt))}(params, curveParams );
60+ uninstall ( params.eulerAccount);
5861
59- checkEulerAccountOperators ( params.eulerAccount, address (pool) );
62+ EulerSwap pool = new EulerSwap {salt: keccak256 ( abi.encode ( params.eulerAccount, salt))}(params, curveParams );
6063
61- allPools. push ( address (pool));
64+ updateEulerAccountState (params.eulerAccount, address (pool));
6265
6366 EulerSwap (pool).activate ();
6467
@@ -81,6 +84,11 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
8184 return address (pool);
8285 }
8386
87+ /// @inheritdoc IEulerSwapFactory
88+ function uninstallPool () external {
89+ uninstall (_msgSender ());
90+ }
91+
8492 /// @inheritdoc IEulerSwapFactory
8593 function computePoolAddress (
8694 IEulerSwap.Params memory poolParams ,
@@ -105,43 +113,127 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
105113 );
106114 }
107115
116+ /// @inheritdoc IEulerSwapFactory
108117 function EVC () external view override (EVCUtil, IEulerSwapFactory) returns (address ) {
109118 return address (evc);
110119 }
111120
112121 /// @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 ) {
114128 return allPools.length ;
115129 }
116130
117131 /// @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+ }
127154
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);
129158 }
130159
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.
134161 /// @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 ()) ;
138165
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);
142193
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+ }
144236
145- eulerAccountToPool[eulerAccount] = newPool ;
237+ return slice ;
146238 }
147239}
0 commit comments