Skip to content

Commit 8109224

Browse files
Merge pull request #57 from euler-xyz/merge-hub
Port over cool stuff from hub
2 parents 4237afc + 136eacc commit 8109224

File tree

6 files changed

+400
-57
lines changed

6 files changed

+400
-57
lines changed

script/DeployPool.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ contract DeployPool is ScriptUtil {
5757
evc.batch(items);
5858
vm.stopBroadcast();
5959

60-
address pool = factory.eulerAccountToPool(eulerAccount);
60+
address pool = factory.poolByEulerAccount(eulerAccount);
6161

6262
string memory outputScriptFileName = "DeployPool_output.json";
6363

src/EulerSwapFactory.sol

Lines changed: 120 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";
1111
/// @author Euler Labs (https://www.eulerlabs.com/)
1212
contract 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
}

src/interfaces/IEulerSwapFactory.sol

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ pragma solidity >=0.8.0;
44
import {IEulerSwap} from "./IEulerSwap.sol";
55

66
interface IEulerSwapFactory {
7+
struct EulerAccountState {
8+
address pool;
9+
uint48 allPoolsIndex;
10+
uint48 poolMapIndex;
11+
}
12+
713
/// @notice Deploy a new EulerSwap pool with the given parameters
814
/// @dev The pool address is deterministically generated using CREATE2 with a salt derived from
915
/// the euler account address and provided salt parameter. This allows the pool address to be
@@ -16,6 +22,12 @@ interface IEulerSwapFactory {
1622
external
1723
returns (address);
1824

25+
/// @notice Uninstalls the pool associated with the Euler account
26+
/// @dev This function removes the pool from the factory's tracking and emits a PoolUninstalled event
27+
/// @dev The function can only be called by the Euler account that owns the pool
28+
/// @dev If no pool is installed for the caller, the function returns without any action
29+
function uninstallPool() external;
30+
1931
/// @notice Compute the address of a new EulerSwap pool with the given parameters
2032
/// @dev The pool address is deterministically generated using CREATE2 with a salt derived from
2133
/// the euler account address and provided salt parameter. This allows the pool address to be
@@ -29,17 +41,57 @@ interface IEulerSwapFactory {
2941
IEulerSwap.CurveParams memory curveParams,
3042
bytes32 salt
3143
) external view returns (address);
44+
45+
/// @notice Returns the address of the Ethereum Vault Connector (EVC) contract
46+
/// @return The address of the EVC contract
3247
function EVC() external view returns (address);
33-
/// @notice Get the length of `allPools` array.
34-
/// @return `allPools` length.
35-
function allPoolsLength() external view returns (uint256);
36-
/// @notice Get the address of the pool at the given index in the `allPools` array.
37-
/// @param index The index of the pool to retrieve.
38-
/// @return The address of the pool at the given index.
39-
function allPools(uint256 index) external view returns (address);
40-
/// @notice Get a slice of the deployed pools array.
41-
/// @param start Start index of the slice.
42-
/// @param end End index of the slice.
43-
/// @return An array containing the slice of the deployed pools.
44-
function getAllPoolsListSlice(uint256 start, uint256 end) external view returns (address[] memory);
48+
49+
/// @notice Returns a slice of all deployed pools
50+
/// @dev Returns a subset of the pools array from start to end index
51+
/// @param start The starting index of the slice (inclusive)
52+
/// @param end The ending index of the slice (exclusive)
53+
/// @return An array containing the requested slice of pool addresses
54+
function poolsSlice(uint256 start, uint256 end) external view returns (address[] memory);
55+
56+
/// @notice Returns all deployed pools
57+
/// @dev Returns the complete array of all pool addresses
58+
/// @return An array containing all pool addresses
59+
function pools() external view returns (address[] memory);
60+
61+
/// @notice Returns the number of pools for a specific asset pair
62+
/// @dev Returns the length of the pool array for the given asset pair
63+
/// @param asset0 The address of the first asset
64+
/// @param asset1 The address of the second asset
65+
/// @return The number of pools for the specified asset pair
66+
function poolsByPairLength(address asset0, address asset1) external view returns (uint256);
67+
68+
/// @notice Returns a slice of pools for a specific asset pair
69+
/// @dev Returns a subset of the pools array for the given asset pair from start to end index
70+
/// @param asset0 The address of the first asset
71+
/// @param asset1 The address of the second asset
72+
/// @param start The starting index of the slice (inclusive)
73+
/// @param end The ending index of the slice (exclusive)
74+
/// @return An array containing the requested slice of pool addresses for the asset pair
75+
function poolsByPairSlice(address asset0, address asset1, uint256 start, uint256 end)
76+
external
77+
view
78+
returns (address[] memory);
79+
80+
/// @notice Returns all pools for a specific asset pair
81+
/// @dev Returns the complete array of pool addresses for the given asset pair
82+
/// @param asset0 The address of the first asset
83+
/// @param asset1 The address of the second asset
84+
/// @return An array containing all pool addresses for the specified asset pair
85+
function poolsByPair(address asset0, address asset1) external view returns (address[] memory);
86+
87+
/// @notice Returns the pool address associated with a specific holder
88+
/// @dev Returns the pool address from the EulerAccountState mapping for the given holder
89+
/// @param who The address of the holder to query
90+
/// @return The address of the pool associated with the holder
91+
function poolByEulerAccount(address who) external view returns (address);
92+
93+
/// @notice Returns the total number of deployed pools
94+
/// @dev Returns the length of the allPools array
95+
/// @return The total number of pools deployed through the factory
96+
function poolsLength() external view returns (uint256);
4597
}

0 commit comments

Comments
 (0)