@@ -38,17 +38,21 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
38
38
address strategyAdmin = makeAddr ("strategyAdmin " );
39
39
address allowanceTargetOwner = makeAddr ("allowanceTargetOwner " );
40
40
uint256 takerPrivateKey = uint256 (1 );
41
+ uint256 alicePrivateKey = uint256 (2 );
41
42
address taker = vm.addr (takerPrivateKey);
43
+ address alice = vm.addr (alicePrivateKey);
42
44
uint256 defaultExpiry = block .timestamp + 1 ;
43
45
address defaultInputToken = USDT_ADDRESS;
44
46
uint256 defaultInputAmount = 10 * 1e6 ;
45
47
address defaultOutputToken = DAI_ADDRESS;
46
48
address [] defaultPath = [defaultInputToken, defaultOutputToken];
47
49
uint24 [] defaultV3Fees = [3000 ];
48
50
bytes defaultTakerPermit;
51
+ bytes alicePermit;
49
52
SmartOrderStrategy smartStrategy;
50
53
GenericSwap genericSwap;
51
54
GenericSwapData defaultGSData;
55
+ GenericSwapData aliceGSData;
52
56
MockStrategy mockStrategy;
53
57
AllowanceTarget allowanceTarget;
54
58
@@ -62,6 +66,7 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
62
66
63
67
genericSwap = new GenericSwap (UNISWAP_PERMIT2_ADDRESS, address (allowanceTarget));
64
68
smartStrategy = new SmartOrderStrategy (strategyAdmin, address (genericSwap), WETH_ADDRESS);
69
+
65
70
mockStrategy = new MockStrategy ();
66
71
vm.prank (strategyAdmin);
67
72
address [] memory tokenList = new address [](1 );
@@ -72,7 +77,7 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
72
77
73
78
IUniswapV3Quoter v3Quoter = IUniswapV3Quoter (UNISWAP_V3_QUOTER_ADDRESS);
74
79
bytes memory encodedPath = UniswapV3.encodePath (defaultPath, defaultV3Fees);
75
- uint256 expectedOut = v3Quoter.quoteExactInput (encodedPath, defaultInputAmount);
80
+ uint256 expectedOut = v3Quoter.quoteExactInput (encodedPath, defaultInputAmount) - 2 ; // leaving 1 wei in GS and SOS separately
76
81
uint256 minOutputAmount = (expectedOut * 95 ) / 100 ; // default 5% slippage tolerance
77
82
bytes memory routerPayload = abi.encodeCall (
78
83
IUniswapSwapRouter02.exactInputSingle,
@@ -101,6 +106,8 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
101
106
102
107
deal (taker, 100 ether);
103
108
setTokenBalanceAndApprove (taker, UNISWAP_PERMIT2_ADDRESS, tokens, 100000 );
109
+ deal (alice, 100 ether);
110
+ setTokenBalanceAndApprove (alice, UNISWAP_PERMIT2_ADDRESS, tokens, 100000 );
104
111
deal (address (mockStrategy), 100 ether);
105
112
setTokenBalanceAndApprove (address (mockStrategy), UNISWAP_PERMIT2_ADDRESS, tokens, 100000 );
106
113
@@ -156,16 +163,17 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
156
163
Snapshot memory makerMakerToken = BalanceSnapshot.take ({ owner: address (mockStrategy), token: gsData.makerToken });
157
164
158
165
uint256 actualOutput = 900 ;
166
+ uint256 realChangedInGS = actualOutput - 1 ; // leaving 1 wei in GS
159
167
160
168
// 800 < 900 < 1000
161
169
mockStrategy.setOutputAmountAndRecipient (actualOutput, payable (address (genericSwap)));
162
170
vm.expectEmit (true , true , true , true );
163
- emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, actualOutput );
171
+ emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, realChangedInGS );
164
172
vm.prank (taker);
165
173
genericSwap.executeSwap (gsData, defaultTakerPermit);
166
174
167
175
takerTakerToken.assertChange (- int256 (gsData.takerTokenAmount));
168
- takerMakerToken.assertChange (int256 (actualOutput ));
176
+ takerMakerToken.assertChange (int256 (realChangedInGS ));
169
177
makerTakerToken.assertChange (int256 (gsData.takerTokenAmount));
170
178
makerMakerToken.assertChange (- int256 (actualOutput));
171
179
}
@@ -176,19 +184,21 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
176
184
gsData.takerToken = Constant.ETH_ADDRESS;
177
185
gsData.takerTokenAmount = 1 ether ;
178
186
187
+ uint256 realChangedInGS = gsData.makerTokenAmount - 1 ; // leaving 1 wei in GS
188
+
179
189
Snapshot memory takerTakerToken = BalanceSnapshot.take ({ owner: taker, token: gsData.takerToken });
180
190
Snapshot memory takerMakerToken = BalanceSnapshot.take ({ owner: taker, token: gsData.makerToken });
181
191
Snapshot memory makerTakerToken = BalanceSnapshot.take ({ owner: address (mockStrategy), token: gsData.takerToken });
182
192
Snapshot memory makerMakerToken = BalanceSnapshot.take ({ owner: address (mockStrategy), token: gsData.makerToken });
183
193
184
194
mockStrategy.setOutputAmountAndRecipient (gsData.makerTokenAmount, payable (address (genericSwap)));
185
195
vm.expectEmit (true , true , true , true );
186
- emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, gsData.makerTokenAmount );
196
+ emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, realChangedInGS );
187
197
vm.prank (taker);
188
198
genericSwap.executeSwap { value: gsData.takerTokenAmount }(gsData, defaultTakerPermit);
189
199
190
200
takerTakerToken.assertChange (- int256 (gsData.takerTokenAmount));
191
- takerMakerToken.assertChange (int256 (gsData.makerTokenAmount ));
201
+ takerMakerToken.assertChange (int256 (realChangedInGS ));
192
202
makerTakerToken.assertChange (int256 (gsData.takerTokenAmount));
193
203
makerMakerToken.assertChange (- int256 (gsData.makerTokenAmount));
194
204
}
@@ -200,19 +210,21 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
200
210
gsData.makerTokenAmount = 1 ether ;
201
211
gsData.minMakerTokenAmount = 1 ether - 1000 ;
202
212
213
+ uint256 realChangedInGS = gsData.makerTokenAmount - 1 ; // leaving 1 wei in GS
214
+
203
215
Snapshot memory takerTakerToken = BalanceSnapshot.take ({ owner: taker, token: gsData.takerToken });
204
216
Snapshot memory takerMakerToken = BalanceSnapshot.take ({ owner: taker, token: gsData.makerToken });
205
217
Snapshot memory makerTakerToken = BalanceSnapshot.take ({ owner: address (mockStrategy), token: gsData.takerToken });
206
218
Snapshot memory makerMakerToken = BalanceSnapshot.take ({ owner: address (mockStrategy), token: gsData.makerToken });
207
219
208
220
mockStrategy.setOutputAmountAndRecipient (gsData.makerTokenAmount, payable (address (genericSwap)));
209
221
vm.expectEmit (true , true , true , true );
210
- emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, gsData.makerTokenAmount );
222
+ emit Swap (getGSDataHash (gsData), gsData.maker, taker, taker, gsData.takerToken, gsData.takerTokenAmount, gsData.makerToken, realChangedInGS );
211
223
vm.prank (taker);
212
224
genericSwap.executeSwap (gsData, defaultTakerPermit);
213
225
214
226
takerTakerToken.assertChange (- int256 (gsData.takerTokenAmount));
215
- takerMakerToken.assertChange (int256 (gsData.makerTokenAmount ));
227
+ takerMakerToken.assertChange (int256 (realChangedInGS ));
216
228
makerTakerToken.assertChange (int256 (gsData.takerTokenAmount));
217
229
makerMakerToken.assertChange (- int256 (gsData.makerTokenAmount));
218
230
}
@@ -306,4 +318,73 @@ contract GenericSwapTest is Test, Tokens, BalanceUtil, Permit2Helper, SigHelper
306
318
vm.expectRevert (IGenericSwap.AlreadyFilled.selector );
307
319
genericSwap.executeSwapWithSig (defaultGSData, defaultTakerPermit, taker, takerSig);
308
320
}
321
+
322
+ function testLeaveOneWeiWithMultipleUsers () public {
323
+ Snapshot memory takerTakerToken = BalanceSnapshot.take ({ owner: taker, token: defaultGSData.takerToken });
324
+ Snapshot memory takerMakerToken = BalanceSnapshot.take ({ owner: taker, token: defaultGSData.makerToken });
325
+ Snapshot memory gsTakerToken = BalanceSnapshot.take ({ owner: address (genericSwap), token: defaultGSData.takerToken });
326
+ Snapshot memory gsMakerToken = BalanceSnapshot.take ({ owner: address (genericSwap), token: defaultGSData.makerToken });
327
+ Snapshot memory makerTakerToken = BalanceSnapshot.take ({ owner: defaultGSData.maker, token: defaultGSData.takerToken });
328
+ Snapshot memory makerMakerToken = BalanceSnapshot.take ({ owner: defaultGSData.maker, token: defaultGSData.makerToken });
329
+
330
+ // the first user: taker
331
+ // his makerTokenAmount has already been reduced by 2 in the setup function
332
+ // leaving 1 wei in GS and SOS separately
333
+ vm.expectEmit (true , true , true , true );
334
+ emit Swap (
335
+ getGSDataHash (defaultGSData),
336
+ defaultGSData.maker,
337
+ taker,
338
+ taker,
339
+ defaultGSData.takerToken,
340
+ defaultGSData.takerTokenAmount,
341
+ defaultGSData.makerToken,
342
+ defaultGSData.makerTokenAmount
343
+ );
344
+
345
+ vm.prank (taker);
346
+ genericSwap.executeSwap (defaultGSData, defaultTakerPermit);
347
+
348
+ // the second user: Alice
349
+ // his makerTokenAmount is recalculate by `quoteExactInput() function base on the current state`
350
+ // but there is no need to reduce it by 2 this time
351
+ aliceGSData = defaultGSData;
352
+
353
+ IUniswapV3Quoter v3Quoter = IUniswapV3Quoter (UNISWAP_V3_QUOTER_ADDRESS);
354
+ bytes memory encodedPath = UniswapV3.encodePath (defaultPath, defaultV3Fees);
355
+ uint256 aliceExpectedOut = v3Quoter.quoteExactInput (encodedPath, defaultInputAmount);
356
+
357
+ aliceGSData.recipient = payable (alice);
358
+ aliceGSData.makerTokenAmount = aliceExpectedOut;
359
+ alicePermit = getTokenlonPermit2Data (alice, alicePrivateKey, aliceGSData.takerToken, address (genericSwap));
360
+
361
+ Snapshot memory aliceTakerToken = BalanceSnapshot.take ({ owner: alice, token: aliceGSData.takerToken });
362
+ Snapshot memory aliceMakerToken = BalanceSnapshot.take ({ owner: alice, token: aliceGSData.makerToken });
363
+
364
+ vm.expectEmit (true , true , true , true );
365
+
366
+ emit Swap (
367
+ getGSDataHash (aliceGSData),
368
+ aliceGSData.maker,
369
+ alice,
370
+ alice,
371
+ aliceGSData.takerToken,
372
+ aliceGSData.takerTokenAmount,
373
+ aliceGSData.makerToken,
374
+ aliceGSData.makerTokenAmount
375
+ );
376
+
377
+ vm.startPrank (alice);
378
+ genericSwap.executeSwap (aliceGSData, alicePermit);
379
+ vm.stopPrank ();
380
+
381
+ takerTakerToken.assertChange (- int256 (defaultGSData.takerTokenAmount));
382
+ takerMakerToken.assertChange (int256 (defaultGSData.makerTokenAmount));
383
+ aliceTakerToken.assertChange (- int256 (aliceGSData.takerTokenAmount));
384
+ aliceMakerToken.assertChange (int256 (aliceGSData.makerTokenAmount));
385
+ gsTakerToken.assertChange (0 );
386
+ gsMakerToken.assertChange (1 );
387
+ makerTakerToken.assertChange (0 );
388
+ makerMakerToken.assertChange (1 );
389
+ }
309
390
}
0 commit comments