Skip to content

Commit a45539c

Browse files
committed
save state
1 parent 2954f97 commit a45539c

16 files changed

+221
-117
lines changed

snapshots/DirectFillerFillMacroTest.json

-6
This file was deleted.

snapshots/DutchOrderReactorTest.json

-11
This file was deleted.

snapshots/EthOutputDirectFillerTest.json

-4
This file was deleted.

snapshots/EthOutputMockFillContractTest.json

-4
This file was deleted.

snapshots/ExclusiveDutchOrderReactorTest.json

-11
This file was deleted.

snapshots/ExclusiveFillerValidationTest.json

-3
This file was deleted.

snapshots/LimitOrderReactorTest.json

-11
This file was deleted.

snapshots/NonlinearDutchDecayLibTest.json

-12
This file was deleted.

snapshots/PriorityOrderReactorTest.json

-15
This file was deleted.

snapshots/ProtocolFeesGasComparisonTest.json

-8
This file was deleted.

snapshots/SwapRouter02ExecutorTest.json

-4
This file was deleted.

snapshots/V2DutchOrderTest.json

-14
This file was deleted.

snapshots/V3DutchOrderTest.json

-14
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity ^0.8.0;
3+
4+
import {IValidationCallback} from "../interfaces/IValidationCallback.sol";
5+
import {ResolvedOrder} from "../base/ReactorStructs.sol";
6+
import {ISwapRouter02} from "../external/ISwapRouter02.sol";
7+
8+
/// @notice Helper contract to call MixedRouteQuoterV1 and decode the return data
9+
contract MixedRouteQuoterV1Wrapper {
10+
address private immutable quoter;
11+
12+
constructor(address _quoter) {
13+
quoter = _quoter;
14+
}
15+
16+
fallback(bytes calldata data) external returns (bytes memory) {
17+
// quoteExactInput(bytes memory path, uint256 amountIn)
18+
if (msg.sig != 0xcdca1753) {
19+
revert("Invalid function call");
20+
}
21+
22+
(bool success, bytes memory returnData) = address(quoter).call(data);
23+
if (!success) {
24+
revert("Failed to call quoter");
25+
}
26+
27+
(uint256 amountOut,,,) = abi.decode(returnData, (uint256, uint160[], uint32[], uint256));
28+
return abi.encode(amountOut);
29+
}
30+
}
31+
32+
/// @notice Validation contract that checks
33+
/// @dev uses swapRouter02
34+
contract PriceOracleValidation is IValidationCallback {
35+
error FailedToCallValidationContract(bytes reason);
36+
error InsufficientOutput(uint256 minOutput, uint256 actualOutput);
37+
38+
function validate(address, ResolvedOrder calldata resolvedOrder) external view {
39+
(address to, bytes memory data) = abi.decode(resolvedOrder.info.additionalValidationData, (address, bytes));
40+
41+
// No strict interface enforced here
42+
(bool success, bytes memory returnData) = address(to).staticcall(data);
43+
if (!success) {
44+
revert FailedToCallValidationContract(returnData);
45+
}
46+
uint256 amount = abi.decode(returnData, (uint256));
47+
48+
uint256 totalOutputAmount;
49+
for (uint256 i = 0; i < resolvedOrder.outputs.length; i++) {
50+
totalOutputAmount += resolvedOrder.outputs[i].amount;
51+
}
52+
if (amount < totalOutputAmount) {
53+
revert InsufficientOutput(amount, totalOutputAmount);
54+
}
55+
}
56+
}

test/integration/SwapRouter02ExecutorIntegration.t.sol

+57
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import {OutputsBuilder} from "../util/OutputsBuilder.sol";
1313
import {PermitSignature} from "../util/PermitSignature.sol";
1414
import {ISwapRouter02, ExactInputSingleParams} from "../../src/external/ISwapRouter02.sol";
1515
import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
16+
import {
17+
PriceOracleValidation,
18+
MixedRouteQuoterV1Wrapper
19+
} from "../../src/sample-validation-contracts/PriceOracleValidation.sol";
20+
import {IValidationCallback} from "../../src/interfaces/IValidationCallback.sol";
1621

1722
// This set of tests will use a mainnet fork to test integration.
1823
contract SwapRouter02IntegrationTest is Test, PermitSignature {
@@ -27,6 +32,7 @@ contract SwapRouter02IntegrationTest is Test, PermitSignature {
2732
address constant WHALE = 0xF04a5cC80B1E94C69B48f5ee68a08CD2F09A7c3E;
2833
IPermit2 constant PERMIT2 = IPermit2(0x000000000022D473030F116dDEE9F6B43aC78BA3);
2934
uint256 constant ONE = 1000000000000000000;
35+
address constant MIXED_ROUTE_QUOTER = 0x84E44095eeBfEC7793Cd7d5b57B7e401D7f1cA2E;
3036

3137
address swapper;
3238
address swapper2;
@@ -35,6 +41,8 @@ contract SwapRouter02IntegrationTest is Test, PermitSignature {
3541
address filler;
3642
SwapRouter02Executor swapRouter02Executor;
3743
DutchOrderReactor dloReactor;
44+
IValidationCallback priceOracleValidationContract;
45+
MixedRouteQuoterV1Wrapper mixedRouteQuoterV1Wrapper;
3846

3947
function setUp() public {
4048
swapperPrivateKey = 0xbabe;
@@ -45,6 +53,8 @@ contract SwapRouter02IntegrationTest is Test, PermitSignature {
4553
vm.createSelectFork(vm.envString("FOUNDRY_RPC_URL"), 16586505);
4654
dloReactor = new DutchOrderReactor(PERMIT2, address(0));
4755
swapRouter02Executor = new SwapRouter02Executor(address(this), dloReactor, address(this), SWAPROUTER02);
56+
priceOracleValidationContract = IValidationCallback(address(new PriceOracleValidation()));
57+
mixedRouteQuoterV1Wrapper = new MixedRouteQuoterV1Wrapper(MIXED_ROUTE_QUOTER);
4858

4959
// Swapper max approves permit post
5060
vm.prank(swapper);
@@ -410,6 +420,53 @@ contract SwapRouter02IntegrationTest is Test, PermitSignature {
410420
assertEq(address(swapRouter02Executor).balance, 319317550497372609);
411421
}
412422

423+
// Same setup as test above
424+
function testSwapWethToDaiViaV2_priceOracleValidationContract() public {
425+
uint256 inputAmount = 2 * ONE;
426+
address[] memory path = new address[](2);
427+
path[0] = address(WETH);
428+
path[1] = address(DAI);
429+
bytes memory encodedPath = abi.encodePacked(path[0], uint24(uint256(3000)), path[1]);
430+
431+
bytes memory additionalValidationData = abi.encode(
432+
address(mixedRouteQuoterV1Wrapper),
433+
abi.encodeWithSelector(bytes4(keccak256("quoteExactInput(bytes,uint256)")), encodedPath, inputAmount)
434+
);
435+
436+
uint256 outputAmount = 3000 * ONE;
437+
438+
DutchOrder memory order = DutchOrder({
439+
info: OrderInfoBuilder.init(address(dloReactor)).withSwapper(swapper).withDeadline(block.timestamp + 100)
440+
.withValidationContract(priceOracleValidationContract).withValidationData(additionalValidationData),
441+
decayStartTime: block.timestamp - 100,
442+
decayEndTime: block.timestamp + 100,
443+
input: DutchInput(WETH, inputAmount, inputAmount),
444+
outputs: OutputsBuilder.singleDutch(address(DAI), outputAmount, outputAmount, address(swapper))
445+
});
446+
447+
address[] memory tokensToApproveForSwapRouter02 = new address[](1);
448+
tokensToApproveForSwapRouter02[0] = address(WETH);
449+
450+
address[] memory tokensToApproveForReactor = new address[](1);
451+
tokensToApproveForReactor[0] = address(DAI);
452+
bytes[] memory multicallData = new bytes[](1);
453+
454+
multicallData[0] = abi.encodeWithSelector(
455+
ISwapRouter02.swapExactTokensForTokens.selector,
456+
inputAmount,
457+
outputAmount,
458+
path,
459+
address(swapRouter02Executor)
460+
);
461+
swapRouter02Executor.execute(
462+
SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(PERMIT2), order)),
463+
abi.encode(tokensToApproveForSwapRouter02, tokensToApproveForReactor, multicallData)
464+
);
465+
assertEq(WETH.balanceOf(swapper), ONE);
466+
assertEq(DAI.balanceOf(swapper), outputAmount);
467+
assertEq(DAI.balanceOf(address(swapRouter02Executor)), 275438458971501955836);
468+
}
469+
413470
// There is 10 WETH swapRouter02Executor. Test that we can convert it to ETH
414471
// and withdraw successfully.
415472
function testUnwrapWETH() public {

0 commit comments

Comments
 (0)