From 64fb21d381c286068a0718a767213d9751b8cd96 Mon Sep 17 00:00:00 2001 From: Sara Reynolds Date: Mon, 12 Feb 2024 14:46:27 -0500 Subject: [PATCH] remove quoter contract and tests --- src/lens/RelayOrderQuoter.sol | 96 ----- .../foundry-tests/lens/RelayOrderQuoter.t.sol | 395 ------------------ 2 files changed, 491 deletions(-) delete mode 100644 src/lens/RelayOrderQuoter.sol delete mode 100644 test/foundry-tests/lens/RelayOrderQuoter.t.sol diff --git a/src/lens/RelayOrderQuoter.sol b/src/lens/RelayOrderQuoter.sol deleted file mode 100644 index bd77b9e..0000000 --- a/src/lens/RelayOrderQuoter.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity 0.8.24; - -import {SignedOrder} from "UniswapX/src/base/ReactorStructs.sol"; -import {ResolvedInput} from "../base/ReactorStructs.sol"; -import {IRelayOrderReactor} from "../interfaces/IRelayOrderReactor.sol"; -import {IMulticall} from "../interfaces/IMulticall.sol"; - -/// @notice Quoter to be called off-chain to simulate orders to the RelayOrderReactor. -/// Supports calls to execute and multicall. -contract RelayOrderQuoter { - // 32 bytes since OrderInfo struct is statically encoded and the reactor is the first member of that struct. - uint256 constant ORDER_INFO_OFFSET = 32; - - // Execute and multicall return values with 1 element will be encoded as follows. They each have different minimum valid lengths. - // ResolvedInput[] | bytes[] - // 32 bytes, location of first param | 32 bytes, location of the first param - // 32 bytes, length | 32 bytes, length of the bytes array - // 32 bytes, address | 32 bytes, location of the first element - // 32 bytes, address | 32 bytes, value of the first element - // 32 bytes , uint256 - uint256 constant MIN_VALID_REASON_LENGTH_EXECUTE = 160; - uint256 constant MIN_VALID_REASON_LENGTH_MULTICALL = 128; - - function quote(bytes calldata order, bytes calldata sig, address feeRecipient) - external - returns (ResolvedInput[] memory result) - { - bytes memory executeSelector = - abi.encodeWithSelector(IRelayOrderReactor.execute.selector, SignedOrder(order, sig), feeRecipient); - (bool success, bytes memory reason) = _callSelf(address(getReactor(order)), executeSelector); - if (!success) { - result = parseRevertReason(reason); - } - } - - function quoteMulticall(address reactor, bytes[] calldata multicallData) - external - returns (bytes[] memory results) - { - bytes memory multicallSelector = abi.encodeWithSelector(IMulticall.multicall.selector, multicallData); - (bool success, bytes memory reason) = _callSelf(reactor, multicallSelector); - if (!success) { - results = parseMulticallRevertReason(reason); - } - } - - function _callSelf(address reactor, bytes memory reactorSelector) - internal - returns (bool success, bytes memory reason) - { - bytes memory callAndRevertSelector = - abi.encodeWithSelector(RelayOrderQuoter.callAndRevert.selector, reactor, reactorSelector); - (success, reason) = address(this).call(callAndRevertSelector); - } - - function callAndRevert(address reactor, bytes calldata selector) external { - (, bytes memory result) = reactor.call(selector); - assembly { - revert(add(32, result), mload(result)) - } - } - - /// @param order abi-encoded order, including `reactor` as the first encoded struct member - function parseRevertReason( - bytes memory reason // ISignatureTransfer[] - ) private pure returns (ResolvedInput[] memory order) { - // Note that the decoding will error if there are invalid results that error with data > min valid reason (128). - if (reason.length < MIN_VALID_REASON_LENGTH_EXECUTE) { - assembly { - revert(add(32, reason), mload(reason)) - } - } else { - return abi.decode(reason, (ResolvedInput[])); - } - } - - function parseMulticallRevertReason(bytes memory reason) private pure returns (bytes[] memory) { - // Note that the decoding will error if there are invalid results that error with data > min valid reason (128). - if (reason.length < MIN_VALID_REASON_LENGTH_MULTICALL) { - assembly { - revert(add(32, reason), mload(reason)) - } - } else { - return abi.decode(reason, (bytes[])); - } - } - - /// @notice parses the reactor from the order - function getReactor(bytes memory order) public pure returns (IRelayOrderReactor reactor) { - assembly { - let orderInfoOffsetPointer := add(order, ORDER_INFO_OFFSET) - reactor := mload(add(orderInfoOffsetPointer, mload(orderInfoOffsetPointer))) - } - } -} diff --git a/test/foundry-tests/lens/RelayOrderQuoter.t.sol b/test/foundry-tests/lens/RelayOrderQuoter.t.sol deleted file mode 100644 index fe3ebdd..0000000 --- a/test/foundry-tests/lens/RelayOrderQuoter.t.sol +++ /dev/null @@ -1,395 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -pragma solidity ^0.8.0; - -import {Test} from "forge-std/Test.sol"; -import {IPermit2} from "permit2/src/interfaces/IPermit2.sol"; -import {SignatureVerification} from "permit2/src/libraries/SignatureVerification.sol"; -import {DeployPermit2} from "UniswapX/test/util/DeployPermit2.sol"; -import {SignedOrder} from "UniswapX/src/base/ReactorStructs.sol"; -import {RelayOrderReactor} from "../../../src/reactors/RelayOrderReactor.sol"; -import {RelayOrderQuoter} from "../../../src/lens/RelayOrderQuoter.sol"; -import {Input, OrderInfo, RelayOrder, ResolvedInput} from "../../../src/base/ReactorStructs.sol"; -import {ReactorErrors} from "../../../src/base/ReactorErrors.sol"; -import {IRelayOrderReactor} from "../../../src/interfaces/IRelayOrderReactor.sol"; -import {IMulticall} from "../../../src/interfaces/IMulticall.sol"; -import {PermitSignature} from "../util/PermitSignature.sol"; -import {MockUniversalRouter} from "../util/mock/MockUniversalRouter.sol"; -import {MockERC20} from "../util/mock/MockERC20.sol"; - -contract RelayOrderQuoterTest is Test, PermitSignature, DeployPermit2 { - RelayOrderQuoter quoter; - IRelayOrderReactor reactor; - - MockERC20 tokenIn; - address swapper; - IPermit2 permit2; - uint256 swapperPrivateKey; - MockUniversalRouter universalRouter; - - uint256 constant ONE = 10 ** 18; - - error InvalidNonce(); - error SignatureExpired(uint256 deadline); - - function setUp() public { - quoter = new RelayOrderQuoter(); - tokenIn = new MockERC20("Input", "IN", 18); - permit2 = IPermit2(deployPermit2()); - universalRouter = new MockUniversalRouter(); - reactor = new RelayOrderReactor(permit2, address(universalRouter)); - - swapperPrivateKey = 0x1234; - swapper = vm.addr(swapperPrivateKey); - tokenIn.mint(address(swapper), ONE); - } - - function testGetReactor() public { - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](1); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({ - reactor: IRelayOrderReactor(address(0xbeef)), - swapper: address(0), - nonce: 0, - deadline: block.timestamp + 100 - }), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp + 100, - actions: actions, - inputs: inputs - }); - assertEq(address(quoter.getReactor(abi.encode(order))), address(0xbeef)); - } - - function testQuote() public { - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - // Actions len = 0 to avoid the revert in UR. - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp + 100}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp + 100, - actions: actions, - inputs: inputs - }); - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - ResolvedInput[] memory quote = quoter.quote(abi.encode(order), sig, address(this)); - assertEq(address(quote[0].recipient), address(this)); - assertEq(quote[0].amount, ONE); - assertEq(quote[0].token, address(tokenIn)); - } - - function testQuoteMulticall() public { - /// Sign tokenIn permit. - bytes32 digest = keccak256( - abi.encodePacked( - "\x19\x01", - tokenIn.DOMAIN_SEPARATOR(), - keccak256( - abi.encode( - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), - swapper, - address(permit2), - type(uint256).max - 1, // infinite approval - tokenIn.nonces(swapper), - type(uint256).max - 1 // infinite deadline - ) - ) - ) - ); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(swapperPrivateKey, digest); - address signer = ecrecover(digest, v, r, s); - assertEq(signer, swapper); - - bytes memory permitData = - abi.encode(swapper, address(permit2), type(uint256).max - 1, type(uint256).max - 1, v, r, s); - - Input[] memory inputs = new Input[](1); - // Actions len = 0 to avoid the revert in UR. - bytes[] memory actions = new bytes[](0); - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp + 100}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp + 100, - actions: actions, - inputs: inputs - }); - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - - bytes[] memory multicallData = new bytes[](2); - // Permit tokenIn - multicallData[0] = abi.encodeWithSelector(IRelayOrderReactor.permit.selector, tokenIn, permitData); - // Transfer tokenIn - multicallData[1] = abi.encodeWithSelector( - IRelayOrderReactor.execute.selector, SignedOrder(abi.encode(order), sig), address(this) - ); - - bytes[] memory quote = quoter.quoteMulticall(address(reactor), multicallData); - bytes memory permitResult = quote[0]; - (ResolvedInput[] memory transferResult) = abi.decode(quote[1], (ResolvedInput[])); - - assertEq(permitResult.length, 0); // permit returns nothing - - assertEq(transferResult.length, 1); - assertEq(address(transferResult[0].recipient), address(this)); - assertEq(transferResult[0].amount, ONE); - assertEq(transferResult[0].token, address(tokenIn)); - } - - function testQuoteMulticallMinimal() public { - /// Sign usdc permit. - bytes32 digest = keccak256( - abi.encodePacked( - "\x19\x01", - tokenIn.DOMAIN_SEPARATOR(), - keccak256( - abi.encode( - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), - swapper, - address(permit2), - type(uint256).max - 1, // infinite approval - tokenIn.nonces(swapper), - type(uint256).max - 1 // infinite deadline - ) - ) - ) - ); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(swapperPrivateKey, digest); - address signer = ecrecover(digest, v, r, s); - assertEq(signer, swapper); - - bytes memory permitData = - abi.encode(swapper, address(permit2), type(uint256).max - 1, type(uint256).max - 1, v, r, s); - - bytes[] memory multicallData = new bytes[](1); - - multicallData[0] = abi.encodeWithSelector(IRelayOrderReactor.permit.selector, tokenIn, permitData); - - bytes[] memory quote = quoter.quoteMulticall(address(reactor), multicallData); - bytes memory permitResult = quote[0]; - - assertEq(quote.length, 1); // Only permit result is returned - assertEq(permitResult.length, 0); // Permit returns nothing - } - - function testQuoteRevertsDeadlineBeforeEndTime() public { - uint256 deadline = block.timestamp + 10; - uint256 decayEndTime = deadline + 90; - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: deadline}), - decayStartTime: block.timestamp, - decayEndTime: decayEndTime, - actions: actions, - inputs: inputs - }); - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.expectRevert(ReactorErrors.DeadlineBeforeEndTime.selector); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testQuoteRevertsSignatureExpired() public { - uint256 deadline = block.timestamp; - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: deadline}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.warp(block.timestamp + 1); - vm.expectRevert(abi.encodeWithSelector(SignatureExpired.selector, deadline)); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testQuoteRevertsEndTimeBeforeStartTime() public { - uint256 startTime = block.timestamp + 1; - uint256 endTime = block.timestamp; - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: startTime, - decayEndTime: endTime, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.expectRevert(ReactorErrors.EndTimeBeforeStartTime.selector); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testQuoteMulticallRevertsEndTimeBeforeStartTime() public { - /// Sign usdc permit. - bytes32 digest = keccak256( - abi.encodePacked( - "\x19\x01", - tokenIn.DOMAIN_SEPARATOR(), - keccak256( - abi.encode( - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"), - swapper, - address(permit2), - type(uint256).max - 1, // infinite approval - tokenIn.nonces(swapper), - type(uint256).max - 1 // infinite deadline - ) - ) - ) - ); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(swapperPrivateKey, digest); - address signer = ecrecover(digest, v, r, s); - assertEq(signer, swapper); - - bytes memory permitData = - abi.encode(swapper, address(permit2), type(uint256).max - 1, type(uint256).max - 1, v, r, s); - - Input[] memory inputs = new Input[](1); - // Actions len = 0 to avoid the revert in UR. - bytes[] memory actions = new bytes[](0); - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - uint256 startTime = block.timestamp + 1; - uint256 endTime = block.timestamp; - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: startTime, - decayEndTime: endTime, - actions: actions, - inputs: inputs - }); - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - - bytes[] memory multicallData = new bytes[](2); - // Permit tokenIn - multicallData[0] = abi.encodeWithSelector(IRelayOrderReactor.permit.selector, tokenIn, permitData); - // Transfer tokenIn - multicallData[1] = abi.encodeWithSelector( - IRelayOrderReactor.execute.selector, SignedOrder(abi.encode(order), sig), address(this) - ); - - vm.expectRevert(ReactorErrors.EndTimeBeforeStartTime.selector); - quoter.quoteMulticall(address(reactor), multicallData); - } - - function testQuoteRevertsTransferFailed() public { - // no approval so transfer from permit2 will fail - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.expectRevert("TRANSFER_FROM_FAILED"); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testQuoteRevertsUniversalRouterError() public { - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](1); - actions[0] = abi.encode(bytes4(keccak256("FakeSelector()"))); // Will just execute the fallback call and revert. - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.expectRevert(MockUniversalRouter.UniversalRouterError.selector); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testRevertInvalidNonce() public { - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - vm.prank(swapper); - permit2.invalidateUnorderedNonces(0, 1); // Invalidates the first nonce. - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - vm.expectRevert(InvalidNonce.selector); - quoter.quote(abi.encode(order), sig, address(this)); - } - - function testRevertInvalidSigner() public { - tokenIn.forceApprove(swapper, address(permit2), ONE); - - Input[] memory inputs = new Input[](1); - bytes[] memory actions = new bytes[](0); - - inputs[0] = Input({token: address(tokenIn), recipient: address(0), startAmount: ONE, maxAmount: ONE}); - - RelayOrder memory order = RelayOrder({ - info: OrderInfo({reactor: reactor, swapper: swapper, nonce: 0, deadline: block.timestamp}), - decayStartTime: block.timestamp, - decayEndTime: block.timestamp, - actions: actions, - inputs: inputs - }); - - bytes memory sig = signOrder(swapperPrivateKey, address(permit2), order); - order.info.swapper = address(0xbeef); // Incorrect swapper; - vm.expectRevert(SignatureVerification.InvalidSigner.selector); - quoter.quote(abi.encode(order), sig, address(this)); - } -}