Skip to content

Commit 449beb4

Browse files
authored
Merge pull request #26 from euler-xyz/feat/factory
Factory
2 parents ec46a58 + 2cf5493 commit 449beb4

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed

src/EulerSwapFactory.sol

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.27;
3+
4+
import {IEulerSwapFactory} from "./interfaces/IEulerSwapFactory.sol";
5+
import {IEulerSwap, EulerSwap} from "./EulerSwap.sol";
6+
7+
/// @title EulerSwapFactory contract
8+
/// @custom:security-contact [email protected]
9+
/// @author Euler Labs (https://www.eulerlabs.com/)
10+
contract EulerSwapFactory is IEulerSwapFactory {
11+
/// @dev An array to store all pools addresses.
12+
address[] public allPools;
13+
/// @dev Mapping to store pool addresses
14+
mapping(bytes32 poolKey => address pool) public getPool;
15+
16+
event PoolDeployed(
17+
address indexed asset0,
18+
address indexed asset1,
19+
address vault0,
20+
address vault1,
21+
uint256 indexed feeMultiplier,
22+
address swapAccount,
23+
uint256 priceX,
24+
uint256 priceY,
25+
uint256 concentrationX,
26+
uint256 concentrationY,
27+
address pool
28+
);
29+
30+
error InvalidQuery();
31+
error AlreadyDeployed();
32+
33+
/// @notice Deploy EulerSwap pool.
34+
function deployPool(DeployParams memory params) external returns (address) {
35+
EulerSwap pool = new EulerSwap(
36+
IEulerSwap.Params({
37+
vault0: params.vault0,
38+
vault1: params.vault1,
39+
myAccount: params.swapAccount,
40+
debtLimit0: params.debtLimit0,
41+
debtLimit1: params.debtLimit1,
42+
fee: params.fee
43+
}),
44+
IEulerSwap.CurveParams({
45+
priceX: params.priceX,
46+
priceY: params.priceY,
47+
concentrationX: params.concentrationX,
48+
concentrationY: params.concentrationY
49+
})
50+
);
51+
52+
address poolAsset0 = pool.asset0();
53+
address poolAsset1 = pool.asset1();
54+
uint256 feeMultiplier = pool.feeMultiplier();
55+
56+
{
57+
bytes32 poolKey = keccak256(
58+
abi.encode(
59+
poolAsset0,
60+
poolAsset1,
61+
params.vault0,
62+
params.vault1,
63+
params.swapAccount,
64+
feeMultiplier,
65+
params.priceX,
66+
params.priceY,
67+
params.concentrationX,
68+
params.concentrationY
69+
)
70+
);
71+
72+
require(getPool[poolKey] == address(0), AlreadyDeployed());
73+
74+
getPool[poolKey] = address(pool);
75+
allPools.push(address(pool));
76+
}
77+
78+
emit PoolDeployed(
79+
poolAsset0,
80+
poolAsset1,
81+
params.vault0,
82+
params.vault1,
83+
feeMultiplier,
84+
params.swapAccount,
85+
params.priceX,
86+
params.priceY,
87+
params.concentrationX,
88+
params.concentrationY,
89+
address(pool)
90+
);
91+
92+
return address(pool);
93+
}
94+
95+
/// @notice Get the length of `allPools` array.
96+
/// @return `allPools` length.
97+
function allPoolsLength() external view returns (uint256) {
98+
return allPools.length;
99+
}
100+
101+
/// @notice Get a slice of the deployed pools array.
102+
/// @param _start Start index of the slice.
103+
/// @param _end End index of the slice.
104+
/// @return An array containing the slice of the deployed pools.
105+
function getAllPoolsListSlice(uint256 _start, uint256 _end) external view returns (address[] memory) {
106+
uint256 length = allPools.length;
107+
if (_end == type(uint256).max) _end = length;
108+
if (_end < _start || _end > length) revert InvalidQuery();
109+
110+
address[] memory allPoolsList = new address[](_end - _start);
111+
for (uint256 i; i < _end - _start; ++i) {
112+
allPoolsList[i] = allPools[_start + i];
113+
}
114+
115+
return allPoolsList;
116+
}
117+
}

src/interfaces/IEulerSwapFactory.sol

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity >=0.8.0;
3+
4+
interface IEulerSwapFactory {
5+
struct DeployParams {
6+
address vault0;
7+
address vault1;
8+
address swapAccount;
9+
uint256 fee;
10+
uint256 priceX;
11+
uint256 priceY;
12+
uint256 concentrationX;
13+
uint256 concentrationY;
14+
uint112 debtLimit0;
15+
uint112 debtLimit1;
16+
}
17+
18+
function deployPool(DeployParams memory params) external returns (address);
19+
20+
function allPools(uint256 index) external view returns (address);
21+
function getPool(bytes32 poolKey) external view returns (address);
22+
function allPoolsLength() external view returns (uint256);
23+
function getAllPoolsListSlice(uint256 start, uint256 end) external view returns (address[] memory);
24+
}

test/EulerSwapFactoryTest.t.sol

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity ^0.8.24;
3+
4+
import {EulerSwapTestBase, EulerSwap} from "./EulerSwapTestBase.t.sol";
5+
import {EulerSwapFactory, IEulerSwapFactory} from "../src/EulerSwapFactory.sol";
6+
7+
contract EulerSwapFactoryTest is EulerSwapTestBase {
8+
EulerSwapFactory public eulerSwapFactory;
9+
10+
uint256 minFee = 0.0000000000001e18;
11+
12+
function setUp() public virtual override {
13+
super.setUp();
14+
15+
vm.prank(creator);
16+
eulerSwapFactory = new EulerSwapFactory();
17+
}
18+
19+
function testDeployPool() public {
20+
uint256 allPoolsLengthBefore = eulerSwapFactory.allPoolsLength();
21+
22+
vm.prank(creator);
23+
EulerSwap eulerSwap = EulerSwap(
24+
eulerSwapFactory.deployPool(
25+
IEulerSwapFactory.DeployParams(
26+
address(eTST), address(eTST2), holder, 0, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
27+
)
28+
)
29+
);
30+
31+
uint256 allPoolsLengthAfter = eulerSwapFactory.allPoolsLength();
32+
bytes32 poolKey = keccak256(
33+
abi.encode(
34+
eulerSwap.asset0(),
35+
eulerSwap.asset1(),
36+
eulerSwap.vault0(),
37+
eulerSwap.vault1(),
38+
eulerSwap.myAccount(),
39+
eulerSwap.feeMultiplier(),
40+
eulerSwap.priceX(),
41+
eulerSwap.priceY(),
42+
eulerSwap.concentrationX(),
43+
eulerSwap.concentrationY()
44+
)
45+
);
46+
47+
assertEq(allPoolsLengthAfter - allPoolsLengthBefore, 1);
48+
assertEq(eulerSwapFactory.getPool(poolKey), address(eulerSwap));
49+
assertEq(eulerSwapFactory.getPool(poolKey), address(eulerSwap));
50+
51+
address[] memory poolsList = eulerSwapFactory.getAllPoolsListSlice(0, type(uint256).max);
52+
assertEq(poolsList.length, 1);
53+
assertEq(poolsList[0], address(eulerSwap));
54+
assertEq(eulerSwapFactory.allPools(0), address(eulerSwap));
55+
56+
vm.prank(creator);
57+
vm.expectRevert(EulerSwapFactory.AlreadyDeployed.selector);
58+
eulerSwapFactory.deployPool(
59+
IEulerSwapFactory.DeployParams(
60+
address(eTST), address(eTST2), holder, 0, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
61+
)
62+
);
63+
}
64+
65+
function testInvalidGetAllPoolsListSliceQuery() public {
66+
vm.expectRevert(EulerSwapFactory.InvalidQuery.selector);
67+
eulerSwapFactory.getAllPoolsListSlice(1, 0);
68+
}
69+
70+
function testDeployWithAssetsOutOfOrderOrEqual() public {
71+
vm.prank(creator);
72+
vm.expectRevert(EulerSwap.AssetsOutOfOrderOrEqual.selector);
73+
eulerSwapFactory.deployPool(
74+
IEulerSwapFactory.DeployParams(
75+
address(eTST), address(eTST), holder, 0, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
76+
)
77+
);
78+
}
79+
80+
function testDeployWithBadFee() public {
81+
vm.prank(creator);
82+
vm.expectRevert(EulerSwap.BadFee.selector);
83+
eulerSwapFactory.deployPool(
84+
IEulerSwapFactory.DeployParams(
85+
address(eTST), address(eTST2), holder, 1e18, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
86+
)
87+
);
88+
}
89+
}

0 commit comments

Comments
 (0)