-
Notifications
You must be signed in to change notification settings - Fork 131
Expand file tree
/
Copy pathOrderQuoter.sol
More file actions
72 lines (63 loc) · 3.15 KB
/
Copy pathOrderQuoter.sol
File metadata and controls
72 lines (63 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IReactorCallback} from "../interfaces/IReactorCallback.sol";
import {IReactor} from "../interfaces/IReactor.sol";
import {ResolvedOrder, SignedOrder} from "../base/ReactorStructs.sol";
/// @notice Quoter contract for orders
/// @dev note this is meant to be used as an off-chain lens contract to pre-validate generic orders
contract OrderQuoter is IReactorCallback {
/// @notice thrown if reactorCallback receives more than one order
error OrdersLengthIncorrect();
/// @notice offset bytes into the order object to the head of the order info struct
uint256 private constant ORDER_INFO_OFFSET = 64;
/// @notice minimum length of a resolved order object in bytes
uint256 private constant RESOLVED_ORDER_MIN_LENGTH = 192;
/// @notice Quote the given order, returning the ResolvedOrder object which defines
/// the current input and output token amounts required to satisfy it
/// Also bubbles up any reverts that would occur during the processing of the order
/// @param order abi-encoded order, including `reactor` as the first encoded struct member
/// @param sig The order signature
/// @return result The ResolvedOrder
function quote(bytes memory order, bytes memory sig) external returns (ResolvedOrder memory result) {
try IReactor(getReactor(order)).executeWithCallback(SignedOrder(order, sig), bytes("")) {}
catch (bytes memory reason) {
result = parseRevertReason(reason);
}
}
/// @notice Return the reactor of a given order (abi.encoded bytes).
/// @param order abi-encoded order, including `reactor` as the first encoded struct member
/// @return reactor
function getReactor(bytes memory order) public pure returns (IReactor reactor) {
assembly {
let orderInfoOffsetPointer := add(order, ORDER_INFO_OFFSET)
reactor := mload(add(orderInfoOffsetPointer, mload(orderInfoOffsetPointer)))
}
}
/// @notice Return the order info of a given order (abi-encoded bytes).
/// @param reason The revert reason
/// @return abi-encoded order, including `reactor` as the first encoded struct member
function parseRevertReason(bytes memory reason) private pure returns (ResolvedOrder memory) {
if (reason.length < RESOLVED_ORDER_MIN_LENGTH) {
assembly {
revert(add(32, reason), mload(reason))
}
} else {
return abi.decode(reason, (ResolvedOrder));
}
}
/// @notice Reactor callback function
/// @dev reverts with the resolved order as reason
/// @param resolvedOrders The resolved orders
function reactorCallback(ResolvedOrder[] memory resolvedOrders, bytes memory) external pure {
if (resolvedOrders.length != 1) {
revert OrdersLengthIncorrect();
}
bytes memory order = abi.encode(resolvedOrders[0]);
assembly {
revert(add(32, order), mload(order))
}
}
/// @notice Fallback function to receive ETH
/// @dev Required for ERC20ETH transfers which send ETH to this contract
receive() external payable {}
}