Skip to content

Commit bf3e362

Browse files
committed
Merge branch 'master' into uninstall-fix
2 parents 3635092 + 6e8a8c8 commit bf3e362

13 files changed

+106
-50
lines changed

src/EulerSwap.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ contract EulerSwap is IEulerSwap, EVCUtil, UniswapHook {
5858
}
5959

6060
/// @inheritdoc IEulerSwap
61-
function activate(InitialState calldata initialState) public {
61+
function activate(InitialState calldata initialState) external {
6262
CtxLib.Storage storage s = CtxLib.getStorage();
6363
Params memory p = CtxLib.getParams();
6464

src/EulerSwapFactory.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
6666

6767
uninstall(params.eulerAccount);
6868

69-
EulerSwap pool = EulerSwap(
70-
MetaProxyDeployer.deployMetaProxy(
71-
eulerSwapImpl, abi.encode(params), keccak256(abi.encode(params.eulerAccount, salt))
72-
)
73-
);
69+
EulerSwap pool = EulerSwap(MetaProxyDeployer.deployMetaProxy(eulerSwapImpl, abi.encode(params), salt));
7470

7571
updateEulerAccountState(params.eulerAccount, address(pool));
7672

@@ -97,7 +93,7 @@ contract EulerSwapFactory is IEulerSwapFactory, EVCUtil, ProtocolFee {
9793
abi.encodePacked(
9894
bytes1(0xff),
9995
address(this),
100-
keccak256(abi.encode(address(poolParams.eulerAccount), salt)),
96+
salt,
10197
keccak256(MetaProxyDeployer.creationCodeMetaProxy(eulerSwapImpl, abi.encode(poolParams)))
10298
)
10399
)

src/libraries/CtxLib.sol

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,15 @@ library CtxLib {
1919
}
2020
}
2121

22+
error InsufficientCalldata();
23+
2224
/// @dev Unpacks encoded Params from trailing calldata. Loosely based on
2325
/// the implementation from EIP-3448 (except length is hard-coded).
26+
/// 384 is the size of the Params struct after ABI encoding.
2427
function getParams() internal pure returns (IEulerSwap.Params memory p) {
25-
bytes memory data;
26-
27-
assembly {
28-
let size := 384
29-
let dataPtr := sub(calldatasize(), size)
30-
data := mload(64)
31-
// increment free memory pointer by metadata size + 32 bytes (length)
32-
mstore(64, add(data, add(size, 32)))
33-
mstore(data, size)
34-
let memPtr := add(data, 32)
35-
calldatacopy(memPtr, dataPtr, size)
28+
require(msg.data.length >= 384, InsufficientCalldata());
29+
unchecked {
30+
return abi.decode(msg.data[msg.data.length - 384:], (IEulerSwap.Params));
3631
}
37-
38-
return abi.decode(data, (IEulerSwap.Params));
3932
}
4033
}

src/libraries/CurveLib.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ library CurveLib {
99
error Overflow();
1010
error CurveViolation();
1111

12-
/// @notice Returns true iff the specified reserve amounts would be acceptable.
12+
/// @notice Returns true if the specified reserve amounts would be acceptable, false otherwise.
1313
/// Acceptable points are on, or above and to-the-right of the swapping curve.
1414
function verify(IEulerSwap.Params memory p, uint256 newReserve0, uint256 newReserve1)
1515
internal
@@ -55,7 +55,7 @@ library CurveLib {
5555
int256 term1 = int256(Math.mulDiv(py * 1e18, y - y0, px, Math.Rounding.Ceil)); // scale: 1e36
5656
int256 term2 = (2 * int256(c) - int256(1e18)) * int256(x0); // scale: 1e36
5757
B = (term1 - term2) / int256(1e18); // scale: 1e18
58-
C = Math.mulDiv((1e18 - c), x0 * x0, 1e18, Math.Rounding.Ceil); // scale: 1e36
58+
C = Math.mulDiv(1e18 - c, x0 * x0, 1e18, Math.Rounding.Ceil); // scale: 1e36
5959
fourAC = Math.mulDiv(4 * c, C, 1e18, Math.Rounding.Ceil); // scale: 1e36
6060
}
6161

@@ -68,7 +68,7 @@ library CurveLib {
6868
unchecked {
6969
squaredB = absB * absB; // scale: 1e36
7070
discriminant = squaredB + fourAC; // scale: 1e36
71-
sqrt = Math.sqrt(discriminant); // // scale: 1e18
71+
sqrt = Math.sqrt(discriminant); // scale: 1e18
7272
sqrt = (sqrt * sqrt < discriminant) ? sqrt + 1 : sqrt;
7373
}
7474
} else {

src/libraries/FundsLib.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ library FundsLib {
7979
uint256 protocolFeeAmount = feeAmount * p.protocolFee / 1e18;
8080

8181
if (protocolFeeAmount != 0) {
82-
IERC20(asset).transfer(p.protocolFeeRecipient, protocolFeeAmount);
82+
IERC20(asset).safeTransfer(p.protocolFeeRecipient, protocolFeeAmount);
8383
amount -= protocolFeeAmount;
8484
feeAmount -= protocolFeeAmount;
8585
}

src/libraries/QuoteLib.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ library QuoteLib {
210210
xNew = reserve0 - amount;
211211
if (xNew < x0) {
212212
// remain on f()
213-
yNew = CurveLib.f(xNew, py, px, y0, x0, cx);
213+
yNew = CurveLib.f(xNew, px, py, x0, y0, cx);
214214
} else {
215215
// move to g()
216216
yNew = CurveLib.fInverse(xNew, py, px, y0, x0, cy);

test/Basic.t.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
pragma solidity ^0.8.24;
33

44
import {IEVault, IEulerSwap, EulerSwapTestBase, EulerSwap, TestERC20} from "./EulerSwapTestBase.t.sol";
5+
import {QuoteLib} from "../src/libraries/QuoteLib.sol";
56

67
contract Basic is EulerSwapTestBase {
78
EulerSwap public eulerSwap;
@@ -40,6 +41,14 @@ contract Basic is EulerSwapTestBase {
4041
assertEq(assetTST2.balanceOf(address(this)), amountOut);
4142
}
4243

44+
function test_badTokenAddrs() public {
45+
vm.expectRevert(QuoteLib.UnsupportedPair.selector);
46+
periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(1234), 0);
47+
48+
vm.expectRevert(QuoteLib.UnsupportedPair.selector);
49+
periphery.quoteExactInput(address(eulerSwap), address(1234), address(assetTST), 0);
50+
}
51+
4352
function test_altPrice() public {
4453
uint256 price = 0.5e18;
4554
uint256 px = price;
@@ -114,6 +123,10 @@ contract Basic is EulerSwapTestBase {
114123

115124
t1.mint(address(this), amount);
116125
uint256 q = periphery.quoteExactInput(address(eulerSwap), address(t1), address(t2), amount);
126+
{
127+
uint256 qRev = periphery.quoteExactOutput(address(eulerSwap), address(t1), address(t2), q);
128+
assertApproxEqAbs(amount, qRev, 200 + (MAX_QUOTE_ERROR + 1) * 2); // max 100:1 price differential, 2 swaps
129+
}
117130

118131
t1.transfer(address(eulerSwap), amount);
119132
if (dir) eulerSwap.swap(0, q, address(this), "");
@@ -122,6 +135,10 @@ contract Basic is EulerSwapTestBase {
122135

123136
t2.mint(address(this), amount2);
124137
uint256 q2 = periphery.quoteExactInput(address(eulerSwap), address(t2), address(t1), amount2);
138+
{
139+
uint256 qRev = periphery.quoteExactOutput(address(eulerSwap), address(t2), address(t1), q2);
140+
assertApproxEqAbs(amount2, qRev, 200 + (MAX_QUOTE_ERROR + 1) * 2);
141+
}
125142

126143
t2.transfer(address(eulerSwap), amount2);
127144
if (dir) eulerSwap.swap(q2, 0, address(this), "");

test/Ctx.t.sol

Lines changed: 29 additions & 1 deletion
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, IEulerSwap} from "./EulerSwapTestBase.t.sol";
4+
import {EulerSwapTestBase, EulerSwap, IEulerSwap} from "./EulerSwapTestBase.t.sol";
55
import {CtxLib} from "../src/libraries/CtxLib.sol";
66

77
contract CtxTest is EulerSwapTestBase {
@@ -17,4 +17,32 @@ contract CtxTest is EulerSwapTestBase {
1717
IEulerSwap.Params memory params = getEulerSwapParams(1e18, 1e18, 1e18, 1e18, 0.4e18, 0.85e18, 0, 0, address(0));
1818
assertEq(abi.encode(params).length, 384);
1919
}
20+
21+
function test_insufficientCalldata() public {
22+
// Proxy appends 384 bytes of calldata, so you can't call directly without this
23+
24+
vm.expectRevert(CtxLib.InsufficientCalldata.selector);
25+
EulerSwap(eulerSwapImpl).getParams();
26+
}
27+
28+
function test_callImplementationDirectly() public {
29+
// Underlying implementation is locked: must call via a proxy
30+
31+
bool success;
32+
33+
vm.expectRevert(EulerSwap.AlreadyActivated.selector);
34+
(success,) = eulerSwapImpl.call(
35+
padCalldata(
36+
abi.encodeCall(EulerSwap.activate, (IEulerSwap.InitialState({currReserve0: 1e18, currReserve1: 1e18})))
37+
)
38+
);
39+
40+
vm.expectRevert(EulerSwap.Locked.selector);
41+
(success,) = eulerSwapImpl.call(padCalldata(abi.encodeCall(EulerSwap.getReserves, ())));
42+
}
43+
44+
function padCalldata(bytes memory inp) internal pure returns (bytes memory) {
45+
IEulerSwap.Params memory params;
46+
return abi.encodePacked(inp, abi.encode(params));
47+
}
2048
}

test/CurveLib.t.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ contract CurveLibTest is EulerSwapTestBase {
3737
// Params
3838
px = 1e18;
3939
py = bound(py, 1, 1e36);
40-
x0 = bound(x0, 1e2, 1e28);
40+
x0 = bound(x0, 1, 1e28);
4141
y0 = bound(y0, 0, 1e28);
4242
cx = bound(cx, 1, 1e18);
4343
cy = bound(cy, 1, 1e18);
@@ -63,9 +63,7 @@ contract CurveLibTest is EulerSwapTestBase {
6363
protocolFeeRecipient: address(0)
6464
});
6565

66-
// Note without -2 in the max bound, f() sometimes fails when x gets too close to centre.
67-
// Note small x values lead to large y-values, which causes problems for both f() and fInverse(), so we cap it here
68-
x = bound(x, 1e2 - 3, x0 - 3);
66+
x = bound(x, 1, x0);
6967

7068
uint256 y = CurveLib.f(x, px, py, x0, y0, cx);
7169
console.log("y ", y);
@@ -83,7 +81,9 @@ contract CurveLibTest is EulerSwapTestBase {
8381

8482
if (x < type(uint112).max && y < type(uint112).max) {
8583
assert(CurveLib.verify(p, xCalc, y));
86-
assert(int256(xCalc) - int256(xBin) <= 3 || int256(yCalc) - int256(yBin) <= 3); // suspect this is 2 wei error in fInverse() + 1 wei error in f()
84+
console.log("Invariant passed");
85+
assert(xCalc - xBin <= 3 || y - yCalc <= 3); // suspect this is 2 wei error in fInverse() + 1 wei error in f()
86+
console.log("Margin error passed");
8787
}
8888
}
8989

test/FactoryTest.t.sol

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ contract FactoryTest is EulerSwapTestBase {
5353
(hookAddress, salt) = HookMiner.find(address(eulerSwapFactory), holder, flags, creationCode);
5454
}
5555

56+
function testDifferingAddressesSameSalt() public view {
57+
(IEulerSwap.Params memory poolParams,) = getBasicParams();
58+
59+
address a1 = eulerSwapFactory.computePoolAddress(poolParams, bytes32(0));
60+
61+
poolParams.eulerAccount = address(123);
62+
63+
address a2 = eulerSwapFactory.computePoolAddress(poolParams, bytes32(0));
64+
65+
assert(a1 != a2);
66+
}
67+
5668
function testDeployPool() public {
5769
uint256 allPoolsLengthBefore = eulerSwapFactory.poolsLength();
5870

@@ -238,16 +250,6 @@ contract FactoryTest is EulerSwapTestBase {
238250
assertEq(pools[0], hookAddress);
239251
}
240252

241-
function testCallImpl() public {
242-
// Underlying implementation is locked: must call via a proxy
243-
244-
vm.expectRevert(EulerSwap.AlreadyActivated.selector);
245-
EulerSwap(eulerSwapImpl).activate(IEulerSwap.InitialState({currReserve0: 1e18, currReserve1: 1e18}));
246-
247-
vm.expectRevert(EulerSwap.Locked.selector);
248-
EulerSwap(eulerSwapImpl).getReserves();
249-
}
250-
251253
address alice = makeAddr("alice");
252254
address bob = makeAddr("bob");
253255

0 commit comments

Comments
 (0)