@@ -19,7 +19,7 @@ contract OrdersTest is Test {
1919 uint256 amount = 200 ;
2020 uint256 deadline = block .timestamp ;
2121
22- event OutputFilled ( uint256 indexed originChainId , address indexed recipient , address indexed token , uint256 amount );
22+ event Filled (Output[] outputs );
2323
2424 event Order (uint256 deadline , Input[] inputs , Output[] outputs );
2525
@@ -176,6 +176,65 @@ contract OrdersTest is Test {
176176 vm.expectRevert (OrderOrigin.OnlyBuilder.selector );
177177 target.sweep (recipient, token);
178178 }
179+
180+ function test_fill_ETH () public {
181+ outputs[0 ].token = address (0 );
182+
183+ vm.expectEmit ();
184+ emit Filled (outputs);
185+ target.fill {value: amount}(outputs);
186+
187+ // ETH is transferred to recipient
188+ assertEq (recipient.balance, amount);
189+ }
190+
191+ function test_fill_ERC20 () public {
192+ vm.expectEmit ();
193+ emit Filled (outputs);
194+ vm.expectCall (token, abi.encodeWithSelector (ERC20 .transferFrom.selector , address (this ), recipient, amount));
195+ target.fill (outputs);
196+ }
197+
198+ function test_fill_both () public {
199+ // add ETH output
200+ outputs.push (Output (address (0 ), amount * 2 , recipient, chainId));
201+
202+ // expect Outputs are filled, ERC20 is transferred
203+ vm.expectEmit ();
204+ emit Filled (outputs);
205+ vm.expectCall (token, abi.encodeWithSelector (ERC20 .transferFrom.selector , address (this ), recipient, amount));
206+ target.fill {value: amount * 2 }(outputs);
207+
208+ // ETH is transferred to recipient
209+ assertEq (recipient.balance, amount * 2 );
210+ }
211+
212+ // fill multiple ETH outputs
213+ function test_fill_multiETH () public {
214+ // change first output to ETH
215+ outputs[0 ].token = address (0 );
216+ // add second ETH oputput
217+ outputs.push (Output (address (0 ), amount * 2 , recipient, chainId));
218+
219+ // expect Order event is initiated
220+ vm.expectEmit ();
221+ emit Filled (outputs);
222+ target.fill {value: amount * 3 }(outputs);
223+
224+ // ETH is transferred to recipient
225+ assertEq (recipient.balance, amount * 3 );
226+ }
227+
228+ function test_fill_underflowETH () public {
229+ // change first output to ETH
230+ outputs[0 ].token = address (0 );
231+ // add second ETH output
232+ outputs.push (Output (address (0 ), 1 , recipient, chainId));
233+
234+ // total ETH outputs should be `amount` + 1; function should underflow only sending `amount`
235+ vm.expectRevert ();
236+ target.fill {value: amount}(outputs);
237+ }
179238}
180239
181240contract OrdersFuzzTest is Test {
@@ -184,7 +243,7 @@ contract OrdersFuzzTest is Test {
184243
185244 uint256 deadline = block .timestamp + 100 ;
186245
187- event OutputFilled ( uint256 indexed originChainId , address indexed recipient , address indexed token , uint256 amount );
246+ event Filled (Output[] outputs );
188247
189248 event Order (uint256 deadline , Input[] inputs , Output[] outputs );
190249
@@ -202,7 +261,7 @@ contract OrdersFuzzTest is Test {
202261
203262 function testFuzz_initiate (Input[] memory fuzzInputs , Output[] memory fuzzOutputs ) public {
204263 // can only use vm.assume 256 * 256 times, and we do 256 fuzz runs
205- vm.assume (fuzzInputs.length < 256 );
264+ vm.assume (fuzzInputs.length < 250 );
206265 // setup the fuzz test by ensuring ETH and ERC20 amounts are available
207266 uint256 totalETH;
208267 for (uint256 i; i < fuzzInputs.length ; i++ ) {
@@ -212,19 +271,7 @@ contract OrdersFuzzTest is Test {
212271 continue ;
213272 }
214273
215- // ERC20 inputs must be one of the tokens we've deployed
216- vm.assume (isToken[fuzzInputs[i].token]);
217- // mint the token amount to ensure the address has it
218- TestERC20 (fuzzInputs[i].token).mint (address (this ), fuzzInputs[i].amount);
219- // approve the target to spend the total token amount
220- TestERC20 (fuzzInputs[i].token).approve (address (target), type (uint256 ).max);
221- // expect the token amount to be transferred
222- vm.expectCall (
223- fuzzInputs[i].token,
224- abi.encodeWithSelector (
225- ERC20 .transferFrom.selector , address (this ), address (target), fuzzInputs[i].amount
226- )
227- );
274+ _setupToken (fuzzInputs[i].token, fuzzInputs[i].amount, address (target));
228275 }
229276 // deal the total ETH amount to ensure the address has it
230277 vm.deal (address (this ), address (this ).balance + totalETH);
@@ -233,4 +280,36 @@ contract OrdersFuzzTest is Test {
233280 emit Order (deadline, fuzzInputs, fuzzOutputs);
234281 target.initiate {value: totalETH}(deadline, fuzzInputs, fuzzOutputs);
235282 }
283+
284+ function testFuzz_fill (Output[] memory fuzzOutputs ) public {
285+ // can only use vm.assume 256 * 256 times, and we do 256 fuzz runs
286+ vm.assume (fuzzOutputs.length < 250 );
287+ // setup the fuzz test by ensuring ETH and ERC20 amounts are available
288+ uint256 totalETH;
289+ for (uint256 i; i < fuzzOutputs.length ; i++ ) {
290+ if (fuzzOutputs[i].token == address (0 )) {
291+ totalETH += fuzzOutputs[i].amount;
292+ continue ;
293+ }
294+
295+ _setupToken (fuzzOutputs[i].token, fuzzOutputs[i].amount, fuzzOutputs[i].recipient);
296+ }
297+ // deal the total ETH amount to ensure the address has it
298+ vm.deal (address (this ), address (this ).balance + totalETH);
299+
300+ vm.expectEmit ();
301+ emit Filled (fuzzOutputs);
302+ target.fill {value: totalETH}(fuzzOutputs);
303+ }
304+
305+ function _setupToken (address token , uint256 amount , address recipient ) internal {
306+ // ERC20 inputs must be one of the tokens we've deployed
307+ vm.assume (isToken[token]);
308+ // mint the token amount to ensure the address has it
309+ TestERC20 (token).mint (address (this ), amount);
310+ // approve the target to spend the total token amount
311+ TestERC20 (token).approve (address (target), type (uint256 ).max);
312+ // expect the token amount to be transferred
313+ vm.expectCall (token, abi.encodeWithSelector (ERC20 .transferFrom.selector , address (this ), recipient, amount));
314+ }
236315}
0 commit comments