11// SPDX-License-Identifier: UNLICENSED
22pragma solidity ^ 0.8.27 ;
33
4+ import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol " ;
5+
46import {IEulerSwapFactory, IEulerSwap} from "./interfaces/IEulerSwapFactory.sol " ;
57import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol " ;
68import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol " ;
@@ -13,15 +15,19 @@ import {MetaProxyDeployer} from "./utils/MetaProxyDeployer.sol";
1315/// @custom:security-contact security@euler.xyz
1416/// @author Euler Labs (https://www.eulerlabs.com/)
1517contract EulerSwapFactory is IEulerSwapFactory , EVCUtil , ProtocolFee {
16- /// @dev An array to store all pools addresses.
17- address [] private allPools;
18+ using EnumerableSet for EnumerableSet.AddressSet;
19+
1820 /// @dev Vaults must be deployed by this factory
1921 address public immutable evkFactory;
2022 /// @dev The EulerSwap code instance that will be proxied to
2123 address public immutable eulerSwapImpl;
22- /// @dev Mapping between euler account and EulerAccountState
23- mapping (address eulerAccount = > EulerAccountState state ) private eulerAccountState;
24- mapping (address asset0 = > mapping (address asset1 = > address [])) private poolMap;
24+
25+ /// @dev Mapping from euler account to pool, if installed
26+ mapping (address eulerAccount = > address ) internal installedPools;
27+ /// @dev Set of all pool addresses
28+ EnumerableSet.AddressSet internal allPools;
29+ /// @dev Mapping from sorted pair of underlyings to set of pools
30+ mapping (address asset0 = > mapping (address asset1 = > EnumerableSet.AddressSet)) internal poolMap;
2531
2632 event PoolDeployed (address indexed asset0 , address indexed asset1 , address indexed eulerAccount , address pool );
2733 event PoolConfig (address indexed pool , IEulerSwap.Params params , IEulerSwap.InitialState initialState );
@@ -98,12 +104,12 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
98104
99105 /// @inheritdoc IEulerSwapFactory
100106 function poolByEulerAccount (address eulerAccount ) external view returns (address ) {
101- return eulerAccountState [eulerAccount].pool ;
107+ return installedPools [eulerAccount];
102108 }
103109
104110 /// @inheritdoc IEulerSwapFactory
105111 function poolsLength () external view returns (uint256 ) {
106- return allPools.length ;
112+ return allPools.length () ;
107113 }
108114
109115 /// @inheritdoc IEulerSwapFactory
@@ -113,12 +119,12 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
113119
114120 /// @inheritdoc IEulerSwapFactory
115121 function pools () external view returns (address [] memory ) {
116- return _getSlice ( allPools, 0 , type ( uint256 ).max );
122+ return allPools. values ( );
117123 }
118124
119125 /// @inheritdoc IEulerSwapFactory
120126 function poolsByPairLength (address asset0 , address asset1 ) external view returns (uint256 ) {
121- return poolMap[asset0][asset1].length ;
127+ return poolMap[asset0][asset1].length () ;
122128 }
123129
124130 /// @inheritdoc IEulerSwapFactory
@@ -132,7 +138,7 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
132138
133139 /// @inheritdoc IEulerSwapFactory
134140 function poolsByPair (address asset0 , address asset1 ) external view returns (address [] memory ) {
135- return _getSlice ( poolMap[asset0][asset1], 0 , type ( uint256 ).max );
141+ return poolMap[asset0][asset1]. values ( );
136142 }
137143
138144 /// @notice Validates operator authorization for euler account and update the relevant EulerAccountState.
@@ -143,16 +149,10 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
143149
144150 (address asset0 , address asset1 ) = _getAssets (newOperator);
145151
146- address [] storage poolMapArray = poolMap[asset0][asset1] ;
152+ installedPools[eulerAccount] = newOperator ;
147153
148- eulerAccountState[eulerAccount] = EulerAccountState ({
149- pool: newOperator,
150- allPoolsIndex: uint48 (allPools.length ),
151- poolMapIndex: uint48 (poolMapArray.length )
152- });
153-
154- allPools.push (newOperator);
155- poolMapArray.push (newOperator);
154+ allPools.add (newOperator);
155+ poolMap[asset0][asset1].add (newOperator);
156156 }
157157
158158 /// @notice Uninstalls the pool associated with the given Euler account
@@ -161,32 +161,22 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
161161 /// @dev If no pool exists for the account, the function returns without any action
162162 /// @param eulerAccount The address of the Euler account whose pool should be uninstalled
163163 function uninstall (address eulerAccount ) internal {
164- address pool = eulerAccountState [eulerAccount].pool ;
164+ address pool = installedPools [eulerAccount];
165165
166166 if (pool == address (0 )) return ;
167167
168168 require (! evc.isAccountOperatorAuthorized (eulerAccount, pool), OldOperatorStillInstalled ());
169169
170170 (address asset0 , address asset1 ) = _getAssets (pool);
171171
172- address [] storage poolMapArr = poolMap[asset0][asset1];
173-
174- swapAndPop (allPools, eulerAccountState[eulerAccount].allPoolsIndex);
175- swapAndPop (poolMapArr, eulerAccountState[eulerAccount].poolMapIndex);
172+ allPools.remove (pool);
173+ poolMap[asset0][asset1].remove (pool);
176174
177- delete eulerAccountState [eulerAccount];
175+ delete installedPools [eulerAccount];
178176
179177 emit PoolUninstalled (asset0, asset1, eulerAccount, pool);
180178 }
181179
182- /// @notice Swaps the element at the given index with the last element and removes the last element
183- /// @param arr The storage array to modify
184- /// @param index The index of the element to remove
185- function swapAndPop (address [] storage arr , uint256 index ) internal {
186- arr[index] = arr[arr.length - 1 ];
187- arr.pop ();
188- }
189-
190180 /// @notice Retrieves the asset addresses for a given pool
191181 /// @dev Calls the pool contract to get its asset0 and asset1 addresses
192182 /// @param pool The address of the pool to query
@@ -202,14 +192,18 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
202192 /// @param start The starting index of the slice (inclusive)
203193 /// @param end The ending index of the slice (exclusive)
204194 /// @return A new memory array containing the requested slice of addresses
205- function _getSlice (address [] storage arr , uint256 start , uint256 end ) internal view returns (address [] memory ) {
206- uint256 length = arr.length ;
195+ function _getSlice (EnumerableSet.AddressSet storage arr , uint256 start , uint256 end )
196+ internal
197+ view
198+ returns (address [] memory )
199+ {
200+ uint256 length = arr.length ();
207201 if (end == type (uint256 ).max) end = length;
208202 if (end < start || end > length) revert SliceOutOfBounds ();
209203
210204 address [] memory slice = new address [](end - start);
211205 for (uint256 i; i < end - start; ++ i) {
212- slice[i] = arr[ start + i] ;
206+ slice[i] = arr. at ( start + i) ;
213207 }
214208
215209 return slice;
0 commit comments