Skip to content

Commit c64b5b5

Browse files
committed
refactor quoting to share logic with getLimits
1 parent 02db36d commit c64b5b5

File tree

2 files changed

+63
-15
lines changed

2 files changed

+63
-15
lines changed

src/EulerSwapPeriphery.sol

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ contract EulerSwapPeriphery is IEulerSwapPeriphery {
1212

1313
error UnsupportedPair();
1414
error OperatorNotInstalled();
15-
error InsufficientReserves();
16-
error InsufficientCash();
15+
error SwapLimitExceeded();
1716
error AmountOutLessThanMin();
1817
error AmountInMoreThanMax();
1918

@@ -93,27 +92,25 @@ contract EulerSwapPeriphery is IEulerSwapPeriphery {
9392
IEVC(eulerSwap.EVC()).isAccountOperatorAuthorized(eulerSwap.eulerAccount(), address(eulerSwap)),
9493
OperatorNotInstalled()
9594
);
95+
require(amount <= type(uint112).max, SwapLimitExceeded());
9696

9797
uint256 feeMultiplier = eulerSwap.feeMultiplier();
98-
address vault0 = eulerSwap.vault0();
99-
address vault1 = eulerSwap.vault1();
10098
(uint112 reserve0, uint112 reserve1,) = eulerSwap.getReserves();
10199

102100
// exactIn: decrease received amountIn, rounding down
103101
if (exactIn) amount = amount * feeMultiplier / 1e18;
104102

105103
bool asset0IsInput = checkTokens(eulerSwap, tokenIn, tokenOut);
104+
(uint256 inLimit, uint256 outLimit) = _getLimits(eulerSwap, asset0IsInput);
106105

107106
uint256 quote = binarySearch(eulerSwap, reserve0, reserve1, amount, exactIn, asset0IsInput);
108107

109108
if (exactIn) {
110109
// if `exactIn`, `quote` is the amount of assets to buy from the AMM
111-
require(quote <= (asset0IsInput ? reserve1 : reserve0), InsufficientReserves());
112-
require(quote <= IEVault(asset0IsInput ? vault1 : vault0).cash(), InsufficientCash());
110+
require(amount <= inLimit && quote <= outLimit, SwapLimitExceeded());
113111
} else {
114112
// if `!exactIn`, `amount` is the amount of assets to buy from the AMM
115-
require(amount <= (asset0IsInput ? reserve1 : reserve0), InsufficientReserves());
116-
require(amount <= IEVault(asset0IsInput ? vault1 : vault0).cash(), InsufficientCash());
113+
require(amount <= outLimit && quote <= inLimit, SwapLimitExceeded());
117114
}
118115

119116
// exactOut: increase required quote(amountIn), rounding up
@@ -161,8 +158,9 @@ contract EulerSwapPeriphery is IEulerSwapPeriphery {
161158

162159
while (low < high) {
163160
uint256 mid = (low + high) / 2;
164-
if (dy == 0 ? eulerSwap.verify(uint256(reserve0New), mid) : eulerSwap.verify(mid, uint256(reserve1New)))
165-
{
161+
(uint256 a, uint256 b) = dy == 0 ? (uint256(reserve0New), mid) : (mid, uint256(reserve1New));
162+
require(a > 0 && b > 0, SwapLimitExceeded());
163+
if (eulerSwap.verify(a, b)) {
166164
high = mid;
167165
} else {
168166
low = mid + 1;
@@ -235,19 +233,22 @@ contract EulerSwapPeriphery is IEulerSwapPeriphery {
235233
return Math.mulDiv(uint256(int256(sqrt) - B), 1e18, A, Math.Rounding.Ceil);
236234
}
237235

238-
/// @dev Max amount the pool can buy of tokenIn and sell of tokenOut
236+
/// @notice Max amount the pool can buy of tokenIn and sell of tokenOut
239237
function getLimits(address eulerSwap, address tokenIn, address tokenOut)
240238
external
241239
view
242240
returns (uint256 inLimit, uint256 outLimit)
243241
{
244-
IEulerSwap es = IEulerSwap(eulerSwap);
245-
if (!IEVC(es.EVC()).isAccountOperatorAuthorized(es.eulerAccount(), eulerSwap)) return (0, 0);
242+
return _getLimits(IEulerSwap(eulerSwap), checkTokens(IEulerSwap(eulerSwap), tokenIn, tokenOut));
243+
}
244+
245+
function _getLimits(IEulerSwap es, bool asset0IsInput) internal view returns (uint256 inLimit, uint256 outLimit) {
246+
if (!IEVC(es.EVC()).isAccountOperatorAuthorized(es.eulerAccount(), address(es))) return (0, 0);
246247

247248
inLimit = outLimit = type(uint112).max;
248-
bool asset0IsInput = checkTokens(es, tokenIn, tokenOut);
249249

250250
// Supply caps on input
251+
251252
{
252253
IEVault vault = IEVault(asset0IsInput ? es.vault0() : es.vault1());
253254
uint256 maxDeposit = vault.debtOf(es.eulerAccount()) + vault.maxDeposit(es.eulerAccount());

test/Limits.t.sol

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ contract LimitsTest is EulerSwapTestBase {
99
function setUp() public virtual override {
1010
super.setUp();
1111

12-
eulerSwap = createEulerSwap(50e18, 50e18, 0, 1e18, 1e18, 0.4e18, 0.85e18);
12+
eulerSwap = createEulerSwap(50e18, 50e18, 0, 1e18, 1e18, 0.9e18, 0.9e18);
1313
}
1414

1515
function test_basicLimits() public {
@@ -18,6 +18,33 @@ contract LimitsTest is EulerSwapTestBase {
1818

1919
assertEq(inLimit, type(uint112).max - 110e18); // max uint minus 110 (100 deposited by depositor, 10 by holder)
2020
assertEq(outLimit, 60e18);
21+
22+
// Exact output
23+
24+
uint256 quote = periphery.quoteExactOutput(address(eulerSwap), address(assetTST), address(assetTST2), 50e18);
25+
assertEq(quote, 75e18);
26+
27+
quote = periphery.quoteExactOutput(address(eulerSwap), address(assetTST), address(assetTST2), 59.9999999e18);
28+
assertApproxEqAbs(quote, 3.6e27, 0.1e27);
29+
30+
vm.expectRevert(EulerSwapPeriphery.SwapLimitExceeded.selector);
31+
quote = periphery.quoteExactOutput(address(eulerSwap), address(assetTST), address(assetTST2), 60e18);
32+
33+
vm.expectRevert(EulerSwapPeriphery.SwapLimitExceeded.selector);
34+
quote = periphery.quoteExactOutput(address(eulerSwap), address(assetTST), address(assetTST2), 60.000001e18);
35+
36+
// Exact input
37+
38+
vm.expectRevert(EulerSwapPeriphery.SwapLimitExceeded.selector);
39+
quote = periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), type(uint112).max);
40+
}
41+
42+
function test_basicLimitsReverse() public view {
43+
(uint256 inLimit, uint256 outLimit) =
44+
periphery.getLimits(address(eulerSwap), address(assetTST2), address(assetTST));
45+
46+
assertEq(outLimit, 60e18);
47+
assertEq(inLimit, type(uint112).max - 110e18);
2148
}
2249

2350
function test_supplyCapExceeded() public {
@@ -28,6 +55,19 @@ contract LimitsTest is EulerSwapTestBase {
2855

2956
assertEq(inLimit, 0); // cap exceeded
3057
assertEq(outLimit, 60e18);
58+
59+
vm.expectRevert(EulerSwapPeriphery.SwapLimitExceeded.selector);
60+
periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), 1);
61+
}
62+
63+
function test_supplyCapExceededReverse() public {
64+
eTST2.setCaps(uint16(2.72e2 << 6) | 18, 0);
65+
66+
(uint256 inLimit, uint256 outLimit) =
67+
periphery.getLimits(address(eulerSwap), address(assetTST2), address(assetTST));
68+
69+
assertEq(inLimit, 0); // cap exceeded
70+
assertEq(outLimit, 60e18);
3171
}
3272

3373
function test_supplyCapExtra() public {
@@ -38,6 +78,13 @@ contract LimitsTest is EulerSwapTestBase {
3878

3979
assertEq(inLimit, 162e18); // 272 - 110
4080
assertEq(outLimit, 60e18);
81+
82+
uint256 quote =
83+
periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), 161.9999e18);
84+
assertApproxEqAbs(quote, 56.9e18, 0.1e18);
85+
86+
vm.expectRevert(EulerSwapPeriphery.SwapLimitExceeded.selector);
87+
periphery.quoteExactInput(address(eulerSwap), address(assetTST), address(assetTST2), 162e18 + 1);
4188
}
4289

4390
function test_utilisation() public {

0 commit comments

Comments
 (0)