Skip to content

Commit fbb52e0

Browse files
feat: use create2 & check operator
1 parent cf2d9c0 commit fbb52e0

File tree

4 files changed

+123
-73
lines changed

4 files changed

+123
-73
lines changed

src/EulerSwapFactory.sol

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ pragma solidity ^0.8.27;
33

44
import {IEulerSwapFactory} from "./interfaces/IEulerSwapFactory.sol";
55
import {IEulerSwap, EulerSwap} from "./EulerSwap.sol";
6+
import {EVCUtil} from "ethereum-vault-connector/utils/EVCUtil.sol";
67

78
/// @title EulerSwapFactory contract
89
/// @custom:security-contact [email protected]
910
/// @author Euler Labs (https://www.eulerlabs.com/)
10-
contract EulerSwapFactory is IEulerSwapFactory {
11+
contract EulerSwapFactory is IEulerSwapFactory, EVCUtil {
1112
/// @dev An array to store all pools addresses.
1213
address[] public allPools;
13-
/// @dev Mapping to store pool addresses
14-
mapping(bytes32 poolKey => address pool) public getPool;
14+
/// @dev Mapping between a swap account and deployed pool that is currently set as operator
15+
mapping(address swapAccount => address operator) public swapAccountToPool;
1516

1617
event PoolDeployed(
1718
address indexed asset0,
@@ -28,11 +29,17 @@ contract EulerSwapFactory is IEulerSwapFactory {
2829
);
2930

3031
error InvalidQuery();
31-
error AlreadyDeployed();
32+
error Unauthorized();
33+
error OldOperatorStillInstalled();
34+
error OperatorNotInstalled();
35+
36+
constructor(address evc) EVCUtil(evc) {}
3237

3338
/// @notice Deploy EulerSwap pool.
34-
function deployPool(DeployParams memory params) external returns (address) {
35-
EulerSwap pool = new EulerSwap(
39+
function deployPool(DeployParams memory params, bytes32 salt) external returns (address) {
40+
require(_msgSender() == params.swapAccount, Unauthorized());
41+
42+
EulerSwap pool = new EulerSwap{salt: keccak256(abi.encode(params.swapAccount, salt))}(
3643
IEulerSwap.Params({
3744
vault0: params.vault0,
3845
vault1: params.vault1,
@@ -49,38 +56,18 @@ contract EulerSwapFactory is IEulerSwapFactory {
4956
})
5057
);
5158

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-
}
59+
checkSwapAccountOperators(params.swapAccount, address(pool));
60+
61+
EulerSwap(pool).activate();
62+
63+
allPools.push(address(pool));
7764

7865
emit PoolDeployed(
79-
poolAsset0,
80-
poolAsset1,
66+
pool.asset0(),
67+
pool.asset1(),
8168
params.vault0,
8269
params.vault1,
83-
feeMultiplier,
70+
pool.feeMultiplier(),
8471
params.swapAccount,
8572
params.priceX,
8673
params.priceY,
@@ -114,4 +101,16 @@ contract EulerSwapFactory is IEulerSwapFactory {
114101

115102
return allPoolsList;
116103
}
104+
105+
function checkSwapAccountOperators(address swapAccount, address newPool) internal {
106+
address operator = swapAccountToPool[swapAccount];
107+
108+
if (operator != address(0)) {
109+
require(!evc.isAccountOperatorAuthorized(swapAccount, operator), OldOperatorStillInstalled());
110+
}
111+
112+
require(evc.isAccountOperatorAuthorized(swapAccount, newPool), OperatorNotInstalled());
113+
114+
swapAccountToPool[swapAccount] = newPool;
115+
}
117116
}

src/interfaces/IEulerSwapFactory.sol

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ interface IEulerSwapFactory {
1515
uint112 debtLimit1;
1616
}
1717

18-
function deployPool(DeployParams memory params) external returns (address);
18+
function deployPool(DeployParams memory params, bytes32 salt) external returns (address);
1919

2020
function allPools(uint256 index) external view returns (address);
21-
function getPool(bytes32 poolKey) external view returns (address);
2221
function allPoolsLength() external view returns (uint256);
2322
function getAllPoolsListSlice(uint256 start, uint256 end) external view returns (address[] memory);
2423
}

test/EulerSwapFactoryTest.t.sol

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22
pragma solidity ^0.8.24;
33

4-
import {EulerSwapTestBase, EulerSwap} from "./EulerSwapTestBase.t.sol";
4+
import {EulerSwapTestBase, IEulerSwap, IEVC, EulerSwap} from "./EulerSwapTestBase.t.sol";
55
import {EulerSwapFactory, IEulerSwapFactory} from "../src/EulerSwapFactory.sol";
66

77
contract EulerSwapFactoryTest is EulerSwapTestBase {
@@ -13,53 +13,58 @@ contract EulerSwapFactoryTest is EulerSwapTestBase {
1313
super.setUp();
1414

1515
vm.prank(creator);
16-
eulerSwapFactory = new EulerSwapFactory();
16+
eulerSwapFactory = new EulerSwapFactory(address(evc));
1717
}
1818

1919
function testDeployPool() public {
2020
uint256 allPoolsLengthBefore = eulerSwapFactory.allPoolsLength();
2121

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-
)
22+
IEulerSwapFactory.DeployParams memory deployParams = IEulerSwapFactory.DeployParams(
23+
address(eTST), address(eTST2), holder, 0, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
2924
);
25+
bytes32 salt = bytes32(uint256(1234));
3026

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-
);
27+
address predictedAddress = predictPoolAddress(address(eulerSwapFactory), deployParams, salt);
28+
29+
IEVC.BatchItem[] memory items = new IEVC.BatchItem[](2);
4630

31+
items[0] = IEVC.BatchItem({
32+
onBehalfOfAccount: address(0),
33+
targetContract: address(evc),
34+
value: 0,
35+
data: abi.encodeCall(evc.setAccountOperator, (holder, predictedAddress, true))
36+
});
37+
items[1] = IEVC.BatchItem({
38+
onBehalfOfAccount: holder,
39+
targetContract: address(eulerSwapFactory),
40+
value: 0,
41+
data: abi.encodeCall(EulerSwapFactory.deployPool, (deployParams, salt))
42+
});
43+
44+
vm.prank(holder);
45+
evc.batch(items);
46+
47+
EulerSwap eulerSwap = EulerSwap(eulerSwapFactory.swapAccountToPool(holder));
48+
49+
uint256 allPoolsLengthAfter = eulerSwapFactory.allPoolsLength();
4750
assertEq(allPoolsLengthAfter - allPoolsLengthBefore, 1);
48-
assertEq(eulerSwapFactory.getPool(poolKey), address(eulerSwap));
49-
assertEq(eulerSwapFactory.getPool(poolKey), address(eulerSwap));
5051

5152
address[] memory poolsList = eulerSwapFactory.getAllPoolsListSlice(0, type(uint256).max);
5253
assertEq(poolsList.length, 1);
5354
assertEq(poolsList[0], address(eulerSwap));
5455
assertEq(eulerSwapFactory.allPools(0), address(eulerSwap));
5556

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-
);
57+
items = new IEVC.BatchItem[](1);
58+
items[0] = IEVC.BatchItem({
59+
onBehalfOfAccount: holder,
60+
targetContract: address(eulerSwapFactory),
61+
value: 0,
62+
data: abi.encodeCall(EulerSwapFactory.deployPool, (deployParams, bytes32(uint256(12345))))
63+
});
64+
65+
vm.prank(holder);
66+
vm.expectRevert(EulerSwapFactory.OldOperatorStillInstalled.selector);
67+
evc.batch(items);
6368
}
6469

6570
function testInvalidGetAllPoolsListSliceQuery() public {
@@ -68,21 +73,68 @@ contract EulerSwapFactoryTest is EulerSwapTestBase {
6873
}
6974

7075
function testDeployWithAssetsOutOfOrderOrEqual() public {
71-
vm.prank(creator);
76+
bytes32 salt = bytes32(uint256(1234));
77+
78+
vm.prank(holder);
7279
vm.expectRevert(EulerSwap.AssetsOutOfOrderOrEqual.selector);
7380
eulerSwapFactory.deployPool(
7481
IEulerSwapFactory.DeployParams(
7582
address(eTST), address(eTST), holder, 0, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
76-
)
83+
),
84+
salt
7785
);
7886
}
7987

8088
function testDeployWithBadFee() public {
81-
vm.prank(creator);
89+
bytes32 salt = bytes32(uint256(1234));
90+
91+
vm.prank(holder);
8292
vm.expectRevert(EulerSwap.BadFee.selector);
8393
eulerSwapFactory.deployPool(
8494
IEulerSwapFactory.DeployParams(
8595
address(eTST), address(eTST2), holder, 1e18, 1e18, 1e18, 0.4e18, 0.85e18, 50e18, 50e18
96+
),
97+
salt
98+
);
99+
}
100+
101+
function predictPoolAddress(address factoryAddress, IEulerSwapFactory.DeployParams memory params, bytes32 salt)
102+
internal
103+
pure
104+
returns (address)
105+
{
106+
return address(
107+
uint160(
108+
uint256(
109+
keccak256(
110+
abi.encodePacked(
111+
bytes1(0xff),
112+
factoryAddress,
113+
keccak256(abi.encode(address(params.swapAccount), salt)),
114+
keccak256(
115+
abi.encodePacked(
116+
type(EulerSwap).creationCode,
117+
abi.encode(
118+
IEulerSwap.Params({
119+
vault0: params.vault0,
120+
vault1: params.vault1,
121+
myAccount: params.swapAccount,
122+
debtLimit0: params.debtLimit0,
123+
debtLimit1: params.debtLimit1,
124+
fee: params.fee
125+
}),
126+
IEulerSwap.CurveParams({
127+
priceX: params.priceX,
128+
priceY: params.priceY,
129+
concentrationX: params.concentrationX,
130+
concentrationY: params.concentrationY
131+
})
132+
)
133+
)
134+
)
135+
)
136+
)
137+
)
86138
)
87139
);
88140
}

test/EulerSwapTestBase.t.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pragma solidity ^0.8.24;
44
import {Test, console} from "forge-std/Test.sol";
55
import {EVaultTestBase, TestERC20} from "evk-test/unit/evault/EVaultTestBase.t.sol";
66
import {IEVault} from "evk/EVault/IEVault.sol";
7-
import {IEulerSwap, EulerSwap} from "../src/EulerSwap.sol";
7+
import {IEulerSwap, IEVC, EulerSwap} from "../src/EulerSwap.sol";
88
import {EulerSwapPeriphery} from "../src/EulerSwapPeriphery.sol";
99

1010
contract EulerSwapTestBase is EVaultTestBase {

0 commit comments

Comments
 (0)