Skip to content

Commit

Permalink
feat: improve natspec (#169)
Browse files Browse the repository at this point in the history
Adds missing natspec and removes some unused stuff
  • Loading branch information
marktoda committed Jul 17, 2023
1 parent 53733a9 commit 6de4965
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 33 deletions.
8 changes: 8 additions & 0 deletions src/external/ISwapRouter02.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@ struct ExactInputSingleParams {
uint160 sqrtPriceLimitX96;
}

struct ExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}

interface ISwapRouter02 {
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
function multicall(uint256 deadline, bytes[] calldata data) external payable returns (bytes[] memory results);
function swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to)
Expand Down
13 changes: 0 additions & 13 deletions src/external/IUniV3SwapRouter.sol

This file was deleted.

6 changes: 6 additions & 0 deletions src/lens/OrderQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ contract OrderQuoter is IReactorCallback {
}
}

/// @notice Return the order info of a given order (abi-encoded bytes).
/// @param order abi-encoded order, including `reactor` as the first encoded struct member
function parseRevertReason(bytes memory reason) private pure returns (ResolvedOrder memory order) {
if (reason.length < 192) {
assembly {
Expand All @@ -47,6 +49,10 @@ contract OrderQuoter is IReactorCallback {
}
}

/// @notice Reactor callback function
/// @dev reverts with the resolved order as reason
/// @param resolvedOrders The resolved orders
/// @param filler The filler of the order
function reactorCallback(ResolvedOrder[] memory resolvedOrders, address filler, bytes memory) external view {
require(filler == address(this));
if (resolvedOrders.length != 1) {
Expand Down
6 changes: 6 additions & 0 deletions src/lib/DutchOrderLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,18 @@ library DutchOrderLib {
string internal constant PERMIT2_ORDER_TYPE =
string(abi.encodePacked("DutchOrder witness)", ORDER_TYPE, TOKEN_PERMISSIONS_TYPE));

/// @notice hash the given output
/// @param output the output to hash
/// @return the eip-712 output hash
function hash(DutchOutput memory output) internal pure returns (bytes32) {
return keccak256(
abi.encode(DUTCH_OUTPUT_TYPE_HASH, output.token, output.startAmount, output.endAmount, output.recipient)
);
}

/// @notice hash the given outputs
/// @param outputs the outputs to hash
/// @return the eip-712 outputs hash
function hash(DutchOutput[] memory outputs) internal pure returns (bytes32) {
unchecked {
bytes memory packedHashes = new bytes(32 * outputs.length);
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ExpectedBalanceLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ library ExpectedBalanceLib {
error InsufficientOutput(uint256 actualBalance, uint256 expectedBalance);

/// @notice fetches expected post-fill balances for all recipient-token output pairs
/// @param orders The orders to fetch balances for
function getExpectedBalances(ResolvedOrder[] memory orders)
internal
view
Expand Down Expand Up @@ -91,6 +92,7 @@ library ExpectedBalanceLib {
}

/// @notice Asserts expected balances are satisfied
/// @param expectedBalances The expected balances to check
function check(ExpectedBalance[] memory expectedBalances) internal view {
for (uint256 i = 0; i < expectedBalances.length; i++) {
ExpectedBalance memory expected = expectedBalances[i];
Expand Down
2 changes: 2 additions & 0 deletions src/lib/OrderInfoLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ library OrderInfoLib {
"OrderInfo(address reactor,address swapper,uint256 nonce,uint256 deadline,address additionalValidationContract,bytes additionalValidationData)";
bytes32 internal constant ORDER_INFO_TYPE_HASH = keccak256(ORDER_INFO_TYPE);

/// @notice hash an OrderInfo object
/// @param info The OrderInfo object to hash
function hash(OrderInfo memory info) internal pure returns (bytes32) {
return keccak256(
abi.encode(
Expand Down
4 changes: 3 additions & 1 deletion src/lib/ResolvedOrderLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {ResolvedOrder} from "../base/ReactorStructs.sol";
import {IValidationCallback} from "../interfaces/IValidationCallback.sol";

library ResolvedOrderLib {
/// @notice thrown when the order targets a different reactor
error InvalidReactor();

/// @notice thrown if the order has expired
error DeadlinePassed();
error ValidationFailed();

/// @notice Validates a resolved order, reverting if invalid
/// @param filler The filler of the order
Expand Down
7 changes: 5 additions & 2 deletions src/reactors/BaseReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity ^0.8.0;

import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {SafeCast} from "openzeppelin-contracts/utils/math/SafeCast.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/security/ReentrancyGuard.sol";
import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
Expand All @@ -13,7 +12,7 @@ import {ExpectedBalance, ExpectedBalanceLib} from "../lib/ExpectedBalanceLib.sol
import {IReactorCallback} from "../interfaces/IReactorCallback.sol";
import {IReactor} from "../interfaces/IReactor.sol";
import {ProtocolFees} from "../base/ProtocolFees.sol";
import {SignedOrder, ResolvedOrder, OrderInfo, InputToken, OutputToken} from "../base/ReactorStructs.sol";
import {SignedOrder, ResolvedOrder, OutputToken} from "../base/ReactorStructs.sol";

/// @notice Generic reactor logic for settling off-chain signed orders
/// using arbitrary fill methods specified by a filler
Expand All @@ -28,7 +27,11 @@ abstract contract BaseReactor is IReactor, ReactorEvents, ProtocolFees, Reentran
// the direct filler did not include enough ETH in their call to execute/executeBatch
error InsufficientEth();

/// @notice permit2 address used for token transfers and signature verification
IPermit2 public immutable permit2;

/// @notice special fillContract address used to indicate a direct fill
/// @dev direct fills transfer tokens directly from the filler to the swapper
IReactorCallback public constant DIRECT_FILL = IReactorCallback(address(1));

constructor(IPermit2 _permit2, address _protocolFeeOwner) ProtocolFees(_protocolFeeOwner) {
Expand Down
3 changes: 3 additions & 0 deletions src/reactors/DutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ contract DutchOrderReactor is BaseReactor {
using DutchDecayLib for DutchOutput[];
using DutchDecayLib for DutchInput;

/// @notice thrown when an order's deadline is before its end time
error DeadlineBeforeEndTime();

/// @notice thrown when an order's inputs and outputs both decay
error InputAndOutputDecay();

constructor(IPermit2 _permit2, address _protocolFeeOwner) BaseReactor(_permit2, _protocolFeeOwner) {}
Expand Down
7 changes: 6 additions & 1 deletion src/reactors/ExclusiveDutchOrderReactor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {ExclusivityOverrideLib} from "../lib/ExclusivityOverrideLib.sol";
import {Permit2Lib} from "../lib/Permit2Lib.sol";
import {DutchDecayLib} from "../lib/DutchDecayLib.sol";
import {ExclusiveDutchOrderLib, ExclusiveDutchOrder, DutchOutput, DutchInput} from "../lib/ExclusiveDutchOrderLib.sol";
import {SignedOrder, ResolvedOrder, InputToken, OrderInfo, OutputToken} from "../base/ReactorStructs.sol";
import {SignedOrder, ResolvedOrder, OrderInfo} from "../base/ReactorStructs.sol";

/// @notice Reactor for exclusive dutch orders
contract ExclusiveDutchOrderReactor is BaseReactor {
Expand All @@ -17,8 +17,13 @@ contract ExclusiveDutchOrderReactor is BaseReactor {
using DutchDecayLib for DutchInput;
using ExclusivityOverrideLib for ResolvedOrder;

/// @notice thrown when an order's deadline is before its end time
error DeadlineBeforeEndTime();

/// @notice thrown when an order's end time is before its start time
error OrderEndTimeBeforeStartTime();

/// @notice thrown when an order's inputs and outputs both decay
error InputAndOutputDecay();

constructor(IPermit2 _permit2, address _protocolFeeOwner) BaseReactor(_permit2, _protocolFeeOwner) {}
Expand Down
4 changes: 4 additions & 0 deletions src/sample-validation-contracts/ExclusiveFillerValidation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ contract ExclusiveFillerValidation is IValidationCallback {
/// @notice thrown if the filler does not have fill rights
error NotExclusiveFiller(address filler);

/// @notice verify that the filler exclusivity is satisfied
/// @dev reverts if invalid filler given the exclusivity parameters
/// @param filler The filler of the order
/// @param resolvedOrder The order data to validate
function validate(address filler, ResolvedOrder calldata resolvedOrder) external view {
(address exclusiveFiller, uint256 lastExclusiveTimestamp) =
abi.decode(resolvedOrder.info.additionalValidationData, (address, uint256));
Expand Down
27 changes: 13 additions & 14 deletions test/executors/SwapRouter02Executor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {DeployPermit2} from "../util/DeployPermit2.sol";
import {OrderInfoBuilder} from "../util/OrderInfoBuilder.sol";
import {OutputsBuilder} from "../util/OutputsBuilder.sol";
import {PermitSignature} from "../util/PermitSignature.sol";
import {ISwapRouter02} from "../../src/external/ISwapRouter02.sol";
import {IUniV3SwapRouter} from "../../src/external/IUniV3SwapRouter.sol";
import {ISwapRouter02, ExactInputParams} from "../../src/external/ISwapRouter02.sol";

// This set of tests will use a mock swap router to simulate the Uniswap swap router.
contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployPermit2 {
Expand Down Expand Up @@ -77,13 +76,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: ONE,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);
bytes memory fillData = abi.encode(tokensToApproveForSwapRouter02, multicallData);

ResolvedOrder[] memory resolvedOrders = new ResolvedOrder[](1);
Expand Down Expand Up @@ -122,13 +121,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: ONE,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);

reactor.execute(
SignedOrder(abi.encode(order), signOrder(swapperPrivateKey, address(permit2), order)),
Expand Down Expand Up @@ -161,13 +160,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: ONE,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);

vm.expectRevert("TRANSFER_FAILED");
reactor.execute(
Expand Down Expand Up @@ -216,13 +215,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: inputAmount * 4,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);

reactor.executeBatch(
signedOrders, swapRouter02Executor, abi.encode(tokensToApproveForSwapRouter02, multicallData)
Expand Down Expand Up @@ -251,13 +250,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: ONE,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);

vm.prank(address(0xbeef));
vm.expectRevert(SwapRouter02Executor.CallerNotWhitelisted.selector);
Expand All @@ -278,13 +277,13 @@ contract SwapRouter02ExecutorTest is Test, PermitSignature, GasSnapshot, DeployP
tokensToApproveForSwapRouter02[0] = address(tokenIn);

bytes[] memory multicallData = new bytes[](1);
IUniV3SwapRouter.ExactInputParams memory exactInputParams = IUniV3SwapRouter.ExactInputParams({
ExactInputParams memory exactInputParams = ExactInputParams({
path: abi.encodePacked(tokenIn, FEE, tokenOut),
recipient: address(swapRouter02Executor),
amountIn: ONE,
amountOutMinimum: 0
});
multicallData[0] = abi.encodeWithSelector(IUniV3SwapRouter.exactInput.selector, exactInputParams);
multicallData[0] = abi.encodeWithSelector(ISwapRouter02.exactInput.selector, exactInputParams);
bytes memory fillData = abi.encode(tokensToApproveForSwapRouter02, multicallData);

ResolvedOrder[] memory resolvedOrders = new ResolvedOrder[](1);
Expand Down
4 changes: 2 additions & 2 deletions test/util/mock/MockSwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.0;
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {Path} from "../lib/Path.sol";
import {IUniV3SwapRouter} from "../../../src/external/IUniV3SwapRouter.sol";
import {ISwapRouter02, ExactInputParams} from "../../../src/external/ISwapRouter02.sol";

contract MockSwapRouter {
using SafeTransferLib for ERC20;
Expand All @@ -22,7 +22,7 @@ contract MockSwapRouter {
swapRate = newRate;
}

function exactInput(IUniV3SwapRouter.ExactInputParams calldata params) external returns (uint256 amountOut) {
function exactInput(ExactInputParams calldata params) external returns (uint256 amountOut) {
bytes memory path = params.path;
(address tokenIn,,) = path.decodeFirstPool();

Expand Down

0 comments on commit 6de4965

Please sign in to comment.